Skip to content

Clearer files: selection, cursor, search, details, dialogs - #18

Open
thisisgm wants to merge 20 commits into
omacom:mainfrom
thisisgm:clearer-files
Open

thisisgm wants to merge 20 commits into
omacom:mainfrom
thisisgm:clearer-files

Conversation

@thisisgm

@thisisgm thisisgm commented Nov 11, 2026 •

Copy link
Copy Markdown

A pass over how the files, the details pane, dialogs and the shortcut sheet read, so the accent marks only where the keys are and what is selected, and nothing important is cut or hidden. One commit per change; each says what was wrong and what it does now. The suite goes from 196 to 206 tests, and every test it adds passes with TMPDIR set to a folder with a space in its name.

What you'd notice in the files

  • The selected name reads. It was accent text on the accent tint, dimmer than the names around it (3.8:1 on osaka-jade). It is now the bright text color, and its size and date the normal one, as a lit menu row does.
  • The cursor stays in sight. Moving it by key past the edge of the grid, the list or a column left it out of view; the view now scrolls just enough to show it.
  • The cursor shows when nothing is selected. After Alt+click on the last selected item, Delete, F2 and Return still act on the cursor's item, which now carries a thin accent frame.
  • The pane without the keys is quiet. In a split both panes drew their selection in the accent. The pane the keys don't go to now draws its selection and cursor in a neutral tint, and a right click in it gives it the keys first, so Delete and F2 after the menu act on the file you clicked.
  • Search results are named by their file. A result was named by its whole path, so deep results led with folders and cut their own names. Each now shows its name, with its folder quieter beside or under it; a tile led by its folder drops the date it had no room for. While the caret is in the search field, or Tab has put the keys in the sidebar or the details, the selection is drawn neutral, since the keys are not on it.
  • The notice line keeps the folder. It elided its end, which is where a restore names the folder it put the file back in; it now elides the middle.

The details pane

  • Several selected says so. It now says how many are selected and their size together, or how many are folders, under a plain glyph, with no one file's picture, details or Open button; several of a plugin's items get the plain glyph too. A selection with no cursor is counted too, instead of "Nothing selected".
  • Titles and text previews wrap between words, splitting a word only when it is wider than the pane.
  • Dates read "4:04 PM", not "4:04PM". Qt's en_US time puts a narrow no-break space before AM and PM, which the font draws as none. Format.js swaps it for a plain space, and the details pane's date goes through it too.
  • "Nothing selected" lines up with "This folder is empty" beside it.

Dialogs, menus and the shortcut sheet

  • A dialog dims the whole window. Rename, delete, mount, name clash and format dialogs were drawn inside their pane, so in a split, and beside the details pane, the rest stayed lit. They now dim everything, no pane takes keys while one is open, and the keys go back to the pane when the last one closes.
  • The shortcut sheet shows its scroll bar. Its bar showed only in use, so nothing said rows were below. It now stays shown at rest in the card's margin, in the quiet text color (3:1 or more on every Omarchy theme). In the preview window the sheet takes the keyboard too, so its keys scroll it, not the preview behind it.
  • Menus stop 8 px short of the window edge, and an open submenu's parent keeps a neutral wash instead of the hover accent.

Drops

  • Ctrl copies. A drop on the same drive always moved. Holding Ctrl at the drop now copies, and a drop that copies tells the source app so.
  • The drop target says what will happen, on a folder, a tile's name, empty space or a column: "Move here" or "Copy here", from Ctrl and whether every file comes from another drive (a drop that mixes drives says "Move here", because the files on this drive are moved), and it follows Ctrl pressed or let go with the pointer still. Files already in the target are left out of that choice, as the drop leaves them.

Screenshots

Before on the left, after on the right, osaka-jade at 1100x700, on the current main.

In the window the selected Exports name is bright, and the details date reads 11:22 AM.

In the window the selected Exports name is bright, and the details date reads 11:22 AM.

A selected row in the list.

A selected row in the list.

After Alt+click on the only selected tile, the cursor keeps a thin frame.

After Alt+click on the only selected tile, the cursor keeps a thin frame.

Moving down past the bottom of the grid, the view follows the cursor.

Moving down past the bottom of the grid, the view follows the cursor.

A right click in the left pane gives it the keys; the right pane goes neutral.

A right click in the left pane gives it the keys; the right pane goes neutral.

Searching "harbour" gives results named by file, folder beside it, the first neutral while typing.

Searching "harbour" gives results named by file, folder beside it, the first neutral while typing.

The same search in the list.

The same search in the list.

Two photos selected.

Two photos selected.

A text preview wraps between words.

A text preview wraps between words.

"Nothing selected" lines up with "This folder is empty".

"Nothing selected" lines up with "This folder is empty".

"6:13 PM" in the details pane.

"6:13 PM" in the details pane.

A restore names the folder it put the file back in.

A restore names the folder it put the file back in.

Delete for good in the Trash: the whole window dims.

Delete for good in the Trash: the whole window dims.

The name clash dialog dims the whole window too.

The name clash dialog dims the whole window too.

The shortcut sheet at 1100x700 shows its scroll bar at rest, so the rows below are in reach.

The shortcut sheet at 1100x700 shows its scroll bar at rest, so the rows below are in reach.

A menu pushed up from low in the grid stops 8 px short of the edge.

A menu pushed up from low in the grid stops 8 px short of the edge.

With Open With open, its parent row keeps a neutral wash.

With Open With open, its parent row keeps a neutral wash.

Not pictured are the drop verbs and Ctrl copy (a held drag cannot be shot) and the keyboard returning after a dialog.

@greptile-apps

greptile-apps Bot commented Nov 11, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; no new actionable issues were found.

Summary

This PR improves file selection, search labels, details, dialogs, and drop hints.

  • File views show which item is selected and where the keys are.
  • Search results lead with each file's name and show its folder nearby.
  • The details pane summarizes a group instead of showing one file as its stand-in.
  • Dialogs cover the window, and menus and the shortcut sheet stay clear and usable.
  • File drops show whether they will move or copy, and Ctrl makes them copy.

The previous plugin-icon finding is fixed. No new actionable issues were found. The added tests were reviewed but not run.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Files hover a folder] --> B[Cache whether all files come from other drives]
    B --> C[Check Ctrl while hovering]
    C --> D[Show Copy here or Move here]
    D --> E[Files dropped]
    E --> F[Skip files already in the target]
    F --> G{Ctrl held?}
    G -->|Yes| H[Copy all remaining files]
    G -->|No| I[Move on the same drive; copy from other drives]
Loading

Reviews (14) · Last reviewed commit: "Drop the selection's accent while the ke..." · Reviewed by Greptile

Comment thread src/FileDrop.qml Resolved
@hegjon

hegjon commented Nov 11, 2026

Copy link
Copy Markdown

A note on "The cursor stays in sight": the cursorMoved() change fixes more than the grid. On main (and the 0.1.1 package Omarchy installs) the list and the column view have the same bug, which is easier to hit there:

mkdir /tmp/5000; cd /tmp/5000; touch file-{0001..5000}.txt
folio /tmp/5000        # Ctrl+2 for the list
# hold Down for a few seconds

The cursor runs off the bottom and the list never scrolls. Here is folio 0.1.1 after Down was held for 3 s: the list still shows file-0001 to file-0024, while the details pane names file-0113.

folio 0.1.1 after Down held for 3 s: the list at the top, the details pane on file-0113

I applied the same two lines to main (a2bc0ca) and built it. After 100 Downs the cursor stays on screen in all three views: the list ends on file-101 (a 300-file folder), the grid scrolls row by row to the cursor, and the column view's file column scrolls like the list. Screenshot of the list (Qt 6.12.0, under Hyprland 0.57):

main with the cursorMoved() change after 100 Downs: the list scrolled to file-101

Why it happens: all three views set highlightFollowsCurrentItem: false and have no highlight, so Qt's key navigation changes currentIndex and nothing scrolls. Before this change, only the Shift+arrow and click paths called positionViewAtIndex.

A headless QML test that shows it without folio (fails for views set up like folio's, passes with the change)

QT_QPA_PLATFORM=offscreen /usr/lib/qt6/bin/qmltestrunner -input tst_follow_cursor.qml

import QtQuick
import QtTest

Item {
    id: root
    width: 800
    height: 600

    component FolioList: ListView {
        width: root.width
        height: root.height
        model: 5000
        keyNavigationEnabled: true
        currentIndex: -1
        acceptedButtons: Qt.NoButton
        boundsBehavior: Flickable.StopAtBounds
        highlightFollowsCurrentItem: false
        clip: true
        delegate: Rectangle { width: ListView.view.width; height: 32; color: ListView.isCurrentItem ? "steelblue" : "white" }
    }
    component FolioGrid: GridView {
        width: root.width
        height: root.height
        model: 5000
        cellWidth: 160
        cellHeight: 160
        keyNavigationEnabled: true
        currentIndex: -1
        acceptedButtons: Qt.NoButton
        boundsBehavior: Flickable.StopAtBounds
        highlightFollowsCurrentItem: false
        clip: true
        delegate: Rectangle { width: 150; height: 150; color: GridView.isCurrentItem ? "steelblue" : "white" }
    }

    FolioList { id: folioList; visible: false }
    FolioList {
        id: fixedList
        visible: false
        onCurrentIndexChanged: if (currentIndex >= 0) positionViewAtIndex(currentIndex, ListView.Contain)
    }
    FolioGrid { id: folioGrid; visible: false }
    FolioGrid {
        id: fixedGrid
        visible: false
        onCurrentIndexChanged: if (currentIndex >= 0) positionViewAtIndex(currentIndex, GridView.Contain)
    }

    TestCase {
        name: "FollowCursor"
        when: windowShown

        function test_downKeepsCursorInView_data() {
            return [
                { tag: "folio list", view: folioList },
                { tag: "fixed list", view: fixedList },
                { tag: "folio grid", view: folioGrid },
                { tag: "fixed grid", view: fixedGrid },
            ]
        }

        function test_downKeepsCursorInView(data) {
            const view = data.view
            view.visible = true
            view.forceActiveFocus()
            for (let i = 0; i < 100; ++i)
                keyClick(Qt.Key_Down)
            const item = view.currentItem
            const top = item.y - view.contentY
            const bottom = top + item.height
            const msg = data.tag + ": current index " + view.currentIndex + " at y " + item.y + ", contentY " +
                view.contentY + ", viewport height " + view.height
            view.visible = false
            verify(view.currentIndex > 0, msg)
            verify(top >= 0 && bottom <= view.height, "cursor outside the viewport: " + msg)
        }
    }
}

On Qt 6.12.0:

FAIL!  : ...test_downKeepsCursorInView(folio list) 'cursor outside the viewport: folio list: current index 99 at y 3168, contentY 0, viewport height 600'
PASS   : ...test_downKeepsCursorInView(fixed list)
FAIL!  : ...test_downKeepsCursorInView(folio grid) 'cursor outside the viewport: folio grid: current index 499 at y 15840, contentY 0, viewport height 600'
PASS   : ...test_downKeepsCursorInView(fixed grid)

I tested only Down held, not Up or how the change behaves when the folder is re-read.

@hegjon

hegjon commented Nov 11, 2026

Copy link
Copy Markdown

Tested this PR's head (ceb887d) on a Dell XPS 13 (Omarchy, Qt 6.12.0): it fixes the bug in my comment above. With Down held in a folder of 5000 files, the list now scrolls with the cursor, and with Up held it comes back to the top. After 100 Downs the cursor is in view in the list, the grid and the column view.

hegjon added a commit to hegjon/hypoland that referenced this pull request Nov 11, 2026
…d the soak

Omarchy replaced Nautilus with Files (folio, C++ and Qt Quick) in omacom/omarchy#18378. folio
and folio-scroll are the same two workloads as Nautilus': the icon folder in its grid with
fullscreen toggled twice a second, and the 5000 files in its list with Down held. The soak gets
w_folio (fullscreen toggles, its three views, new windows), w_files_folio and w_search_folio;
scroll_files and search_files take the key that shows the list (CTRL 2 in Files, CTRL 1 in
Nautilus and flea as before). Files keeps its view in ~/.config/folio/folio.conf, which the
workloads set and put back. The Nautilus and flea workloads are unchanged.

Files 0.1.1 and 0.2.0 do not scroll the list to the cursor on Down (omacom/folio#18 fixes it),
so until a release has the fix folio-scroll measures the cursor and the details pane, not
scrolling. The first numbers (T460s, XPS) are in AGENTS.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@thisisgm
thisisgm force-pushed the clearer-files branch 3 times, most recently from 5d6473d to 96eb5b9 Compare November 11, 2026 15:18
Comment thread src/HelpOverlay.qml Resolved
Comment thread src/fileops.cpp Resolved
@thisisgm

Copy link
Copy Markdown
Author

Thanks @hegjon! The same change covers the list and the column view, as your test shows, and the description now says so.

Comment thread src/fileops.cpp Resolved
@thisisgm
thisisgm force-pushed the clearer-files branch 2 times, most recently from 342a67e to 9618295 Compare November 11, 2026 19:46
hegjon added a commit to hegjon/hypoland that referenced this pull request Nov 12, 2026
folio and folio-scroll are skipped where Folio is older than 0.4.0, so
results compare across machines (missing() takes <program>>=<version>,
checked with vercmp). 0.4.0 is installed on all eleven machines. It still
does not scroll the list to the cursor on Down (omacom/folio#18 open).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The selected item's name was drawn in the accent on the accent tint, which
read dimmer than the names around it (3.8:1 on osaka-jade). It now uses the
bright text color, and its size and date the normal one, as a lit menu row does.
Moving the cursor by key past the edge of the grid left it out of sight.
The view now scrolls just enough to show it.
With nothing selected (Alt+click on the last selected item), Delete, F2
and Return still act on the cursor's item, but nothing showed which one.
That item now carries a thin accent frame, the selection ring at 1 px.
In a split both panes drew their selection in the accent, so nothing said
which pane the keys go to beyond the thin line at the top. The pane the
keys don't go to now draws its selection and cursor in a neutral tint.
The details pane wrapped its title and text preview at any letter, so a
name or a line of text broke mid-word. Both now break between words and
split a word only when it is wider than the pane.
The notice line elided its end, which is where a restore names the folder
it put the file back in. It now elides the middle, so the start and the
folder stay readable on a narrow pane.
With several items selected, the details pane still showed only the one
under the cursor, as if it were the whole selection. It now says how many
are selected and their size together, or how many of them are folders.
A search result was named by its whole path from the searched folder, so
deep results led with folders and their own names were cut. Each now shows
its file's name, with the folder it is in quieter beside or under it; a
plugin's item keeps its own name.
Rename, delete, mount, name clash and format dialogs were drawn inside their
folder pane, so in a split, and beside the details pane, the rest stayed lit.
They now dim the whole window, no pane takes keys while one is open, and
the keyboard goes back to the pane once the last one closes.
The fitted shortcut sheet's scroll bar showed only in use, so nothing said
rows were below; it now stays shown in the card's margin. In the preview
window the sheet takes the keyboard, so its keys scroll it, not the preview.
A drop on the same drive always moved, with no way to copy as most file
managers do with Ctrl. Holding Ctrl at the drop now copies, and a drop
that copies tells the source app so instead of saying it moved.
The sheet's scroll bar, shown at rest as the only sign of rows below,
was 1.9:1 on its card. A bar shown at rest now takes the theme's quiet
text color, 3:1 or more on every Omarchy theme; others are unchanged.
A menu could rest on the window's edge, and an open submenu's parent row
wore the same accent as the row under the pointer. Menus now stop 8 px
short of the edge, and the open parent keeps a neutral wash.
Qt's en_US time puts a narrow no-break space before AM and PM, which the
font draws as none, so times read "4:04PM". Format.js now swaps it for a
plain space, and the details pane's date and time go through it too.
Comment thread src/PreviewPane.qml Resolved
With several selected, the details pane drew one of them under "N items
selected", and a selection with no cursor showed "Nothing selected". A
selection is now counted with or without a cursor, under a plain glyph.
A search result tile's line led with its folder, then size and date, so
the date was cut mid-number on a 140 px tile. When the folder leads, the
line holds folder and size; the details pane still gives the date.
A drop could move or copy, but its frame said neither, so the verb was
known only after letting go. Each drop target, columns included, now says
"Move here" or "Copy here", from Ctrl and whether every file is on another
drive.
A right click on a file in the other pane selected it there, but the keys
stayed with the first pane, so Delete and F2 after the menu acted on the
wrong file. A right click now gives the keys to its pane first.
"Nothing selected" sat 8 px above "This folder is empty" beside it,
since the folder view starts 16 px lower than the details pane. It now
drops by half that, so the two read as one line.
While the caret was in the search field, or Tab had put the keyboard in
the sidebar or the details, the selection wore the full accent ring, as if
the keys were on it. The view now draws it as the other pane's until the
keys come back to the files.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants