Skip to content

Implement flags for synchronizing the image list when changing the working directory #792

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
8 changes: 8 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ Added:
* The ``:move-view`` command to move the view in image and thumbnail mode to the top /
center / bottom along with the ``zt``, ``zz`` and ``zb`` bindings. Thanks
`@Markuzcha`_ for the idea!
* The ``--open-selected`` flag for ``:scroll left/right`` in the library. When using
this flag, any images in the new folder are automatically opened. If there are none,
any loaded images are cleared. This comes with the new ``<ctrl-h/j/k/l>`` keybindings
for ``:scroll left/down/up/right`` for a consistent "move and select" flow. Thanks
`@mcp292`_ for the idea!
* The ``--open-images`` flag for the ``:open`` command to emulate the
``--open-selected`` behaviour in ``:scroll left/right`` in the library.

Changed:
^^^^^^^^
Expand Down Expand Up @@ -585,3 +592,4 @@ Initial release of the Qt version.
.. _@xfzv: https://github.com/xfzv
.. _@mozirilla213: https://github.com/mozirilla213
.. _@Markuzcha: https://github.com/Markuzcha
.. _@mcp292: https://github.com/mcp292
14 changes: 14 additions & 0 deletions tests/end2end/features/library/libraryscroll.feature
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,17 @@ Feature: Scrolling the library.
| top |
| center |
| bottom |

Scenario: Scroll right and open selected stored image
Given I open a directory with 3 images
When I run scroll down
When I run scroll left
And I run scroll right --open-selected
Then the library row should be 2
And the image should have the index 2

Scenario: Scroll left and clear the image list
Given I open a directory with 3 images
When I run scroll down --open-selected
And I run scroll left --open-selected
Then the image should have the index 0
7 changes: 6 additions & 1 deletion vimiv/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def pathlist(mode: modes.Mode = None) -> List[str]:

@keybindings.register("o", "command --text='open '")
@commands.register(name="open")
def open_paths(paths: Iterable[str]) -> None:
def open_paths(paths: Iterable[str], open_images: bool = False) -> None:
"""Open one or more paths.

**syntax:** ``:open path [path ...]``
Expand All @@ -65,13 +65,18 @@ def open_paths(paths: Iterable[str]) -> None:

positional arguments:
* ``paths``: The path(s) to open.

optional arguments:
* ``--open-images``: If True, open any images in a new directory automatically.
"""
images, directories = files.supported(paths)
if images:
working_directory.handler.chdir(os.path.dirname(images[0]))
signals.load_images.emit(images)
modes.IMAGE.enter()
elif directories:
# This is always the library, admittedly a bit hacky to access like this
modes.LIBRARY.widget.autoload = open_images # type: ignore [attr-defined]
working_directory.handler.chdir(directories[0])
modes.LIBRARY.enter()
else:
Expand Down
32 changes: 28 additions & 4 deletions vimiv/gui/library.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ class Library(
"""Library widget.

Attributes:
autoload: Load images of new working directory automatically.

_last_selected: Name of the path that was selected last.
_positions: Dictionary that stores positions in directories.
"""
Expand Down Expand Up @@ -87,6 +89,7 @@ def __init__(self, mainwindow: QWidget):
widgets.ScrollWheelCumulativeMixin.__init__(self, self._scroll_wheel_callback)
widgets.FlatTreeView.__init__(self, parent=mainwindow)

self.autoload = False
self._last_selected = ""
self._positions: Dict[str, Position] = {}

Expand Down Expand Up @@ -168,7 +171,7 @@ def _open_path(self, path: str, close: bool):
if not path:
log.warning("Library: selecting empty path")
elif os.path.isdir(path):
self._open_directory(path)
self._open_directory(path, reload_current=False)
else:
self._open_image(path, close)

Expand All @@ -192,17 +195,27 @@ def _open_image(self, path, close):
"<ctrl>d", "scroll half-page-down", mode=api.modes.LIBRARY
)
@api.keybindings.register(
("p", "<button-back>"), "scroll up --open-selected", mode=api.modes.LIBRARY
("p", "<button-back>", "<ctrl-k>"),
"scroll up --open-selected",
mode=api.modes.LIBRARY,
)
@api.keybindings.register("k", "scroll up", mode=api.modes.LIBRARY)
@api.keybindings.register(
("n", "<button-forward>"), "scroll down --open-selected", mode=api.modes.LIBRARY
("n", "<button-forward>", "<ctrl-j>"),
"scroll down --open-selected",
mode=api.modes.LIBRARY,
)
@api.keybindings.register("j", "scroll down", mode=api.modes.LIBRARY)
@api.keybindings.register(
("h", "<button-right>"), "scroll left", mode=api.modes.LIBRARY
)
@api.keybindings.register(
"<ctrl-h>", "scroll left --open-selected", mode=api.modes.LIBRARY
)
@api.keybindings.register("l", "scroll right", mode=api.modes.LIBRARY)
@api.keybindings.register(
"<ctrl-l>", "scroll right --open-selected", mode=api.modes.LIBRARY
)
@api.commands.register(mode=api.modes.LIBRARY)
def scroll( # type: ignore[override]
self,
Expand Down Expand Up @@ -232,13 +245,15 @@ def scroll( # type: ignore[override]
_logger.debug("Scrolling in direction '%s'", direction)
if direction == direction.Right:
current = self.current()
self.autoload = open_selected
# Close library on double selection
self._open_path(current, close=current == self._last_selected)
elif direction == direction.Left:
self.store_position()
parent = os.path.abspath(os.pardir)
self._positions[parent] = Position(os.getcwd())
api.working_directory.handler.chdir(parent)
self.autoload = open_selected
self._open_directory(path=parent)
else:
row = self.row()
if row == -1: # Directory is empty
Expand Down Expand Up @@ -410,6 +425,15 @@ def _update_content(self, images: List[str], directories: List[str]):
self._add_rows(directories, are_directories=True)
self._add_rows(images, are_directories=False)
self._library.load_directory()
if self._library.autoload:
focused_path = self._library.current()
if files.is_image(focused_path):
api.signals.load_images.emit([focused_path])
elif images:
api.signals.load_images.emit(images)
else:
api.signals.all_images_cleared.emit()
self._library.autoload = False

@Slot(list, list)
def _on_directory_changed(self, images: List[str], directories: List[str]):
Expand Down
18 changes: 9 additions & 9 deletions vimiv/imutils/filelist.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ def __init__(self):
slideshow.event.connect(self._on_slideshow_event)

api.signals.load_images.connect(self._on_load_images)
api.signals.all_images_cleared.connect(self._on_images_cleared)
api.working_directory.handler.images_changed.connect(self._on_images_changed)
api.settings.sort.shuffle.changed.connect(self._on_shuffle)

Expand Down Expand Up @@ -227,7 +228,7 @@ def _on_images_changed(
_logger.debug("Adding %s to image filelist", added)
paths = new_paths
if not paths:
_clear()
api.signals.all_images_cleared.emit()
api.status.update("Image filelist cleared")
else:
_load_paths(paths, current())
Expand All @@ -239,6 +240,13 @@ def _on_shuffle(self):
if _paths:
_load_paths(_paths, current())

@utils.slot
def _on_images_cleared(self):
"""Clear all images from the storage as all paths were removed."""
global _paths, _index
_paths = []
_index = 0


def _set_index(index: int, previous: str = None, *, keep_zoom: bool = False) -> None:
"""Set the global _index to index."""
Expand Down Expand Up @@ -286,11 +294,3 @@ def _load_paths(paths: Iterable[str], focused_path: str = None) -> None:
else min(len(paths) - 1, _index)
)
_set_index(index, previous)


def _clear() -> None:
"""Clear all images from the storage as all paths were removed."""
global _paths, _index
_paths = []
_index = 0
api.signals.all_images_cleared.emit()