flea-qml 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (637) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +511 -2
  3. package/THIRD-PARTY-NOTICES.md +29 -0
  4. package/demos/App.java +5 -0
  5. package/demos/Dockerfile +4 -0
  6. package/demos/Main.kt +3 -0
  7. package/demos/Program.cs +1 -0
  8. package/demos/README.md +12 -0
  9. package/demos/app.dart +3 -0
  10. package/demos/app.deb +0 -0
  11. package/demos/app.js +1 -0
  12. package/demos/backup.tar +0 -0
  13. package/demos/budget.xlsx +0 -0
  14. package/demos/build.sh +2 -0
  15. package/demos/bundle.zip +0 -0
  16. package/demos/clip.mp4 +0 -0
  17. package/demos/data.sqlite +0 -0
  18. package/demos/disk.iso +0 -0
  19. package/demos/engine.cpp +5 -0
  20. package/demos/firmware.bin +0 -0
  21. package/demos/flake.nix +4 -0
  22. package/demos/folder/inside.txt +1 -0
  23. package/demos/font.ttf +0 -0
  24. package/demos/index.html +5 -0
  25. package/demos/index.php +2 -0
  26. package/demos/init.lua +1 -0
  27. package/demos/letter.docx +0 -0
  28. package/demos/lib.rs +3 -0
  29. package/demos/main.c +6 -0
  30. package/demos/main.h +3 -0
  31. package/demos/math-and-diagrams.md +200 -0
  32. package/demos/notes.tar.gz +0 -0
  33. package/demos/notes.txt +3 -0
  34. package/demos/photo.png +0 -0
  35. package/demos/program +2 -0
  36. package/demos/report.pdf +32 -0
  37. package/demos/script.py +1 -0
  38. package/demos/server.go +7 -0
  39. package/demos/settings.json +4 -0
  40. package/demos/slides.pptx +0 -0
  41. package/demos/song.mp3 +0 -0
  42. package/demos/style.css +4 -0
  43. package/demos/tool.rb +1 -0
  44. package/demos/types.ts +2 -0
  45. package/docs/pele.md +23 -0
  46. package/docs/protocol.md +3420 -0
  47. package/docs/temml.md +63 -0
  48. package/index.js +107 -0
  49. package/package.json +34 -4
  50. package/src/archive.js +407 -0
  51. package/src/archiveops.js +728 -0
  52. package/src/backend.js +369 -0
  53. package/src/bulkrename.js +95 -0
  54. package/src/clip-host.js +76 -0
  55. package/src/clip.js +462 -0
  56. package/src/code.js +168 -0
  57. package/src/compare.js +74 -0
  58. package/src/create.js +128 -0
  59. package/src/dirsize.js +147 -0
  60. package/src/figure-svg.js +530 -0
  61. package/src/figure-thread.js +23 -0
  62. package/src/figure.js +132 -0
  63. package/src/find.js +55 -0
  64. package/src/flea.js +39 -0
  65. package/src/fsinfo.js +39 -0
  66. package/src/highlight.js +141 -0
  67. package/src/html.js +52 -0
  68. package/src/kinds.js +89 -0
  69. package/src/listing.js +130 -0
  70. package/src/markdown-html.js +317 -0
  71. package/src/mathml.js +186 -0
  72. package/src/menu.js +180 -0
  73. package/src/meta.js +135 -0
  74. package/src/office.js +810 -0
  75. package/src/order.js +100 -0
  76. package/src/peek.js +49 -0
  77. package/src/pele-wrapper.js +695 -0
  78. package/src/permissions.js +180 -0
  79. package/src/places.js +313 -0
  80. package/src/preview-language.js +10 -0
  81. package/src/terminal-server.js +95 -0
  82. package/src/terminal-shell.js +26 -0
  83. package/src/transfer.js +669 -0
  84. package/src/trash-record.js +41 -0
  85. package/src/trash.js +210 -0
  86. package/src/trashbrowse.js +327 -0
  87. package/src/uistate.js +393 -0
  88. package/src/uistore.js +168 -0
  89. package/src/vendor/LICENSES/Apache-2.0.txt +202 -0
  90. package/src/vendor/LICENSES/MIT-katex-2015.txt +27 -0
  91. package/src/vendor/LICENSES/MIT-katex.txt +21 -0
  92. package/src/vendor/LICENSES/MIT-mermaid.txt +21 -0
  93. package/src/vendor/LICENSES/MIT-pele.txt +40 -0
  94. package/src/vendor/LICENSES/MIT-perseus.txt +18 -0
  95. package/src/vendor/LICENSES/MIT-temml.txt +21 -0
  96. package/src/vendor/pele.js +145 -0
  97. package/src/vendor/temml.mjs +14708 -0
  98. package/src/watch.js +98 -0
  99. package/src/wayland/client.js +109 -0
  100. package/src/wayland/protocol.js +55 -0
  101. package/src/wayland/protocols/ext-data-control-v1.xml +276 -0
  102. package/src/wayland/protocols/wayland.xml +3248 -0
  103. package/src/wayland/protocols/wlr-data-control-unstable-v1.xml +278 -0
  104. package/src/wayland/resource-io.js +6 -0
  105. package/src/wayland/socket-discovery.js +26 -0
  106. package/src/wayland/transport-posix.js +120 -0
  107. package/src/wayland/transport-win32.js +11 -0
  108. package/src/wayland/transport.js +3 -0
  109. package/src/wayland/win32-resources.js +80 -0
  110. package/src/wayland/win32-wire.js +62 -0
  111. package/test/archive.test.js +80 -0
  112. package/test/bench-markdown-scroll.mjs +190 -0
  113. package/test/clip-host.test.js +113 -0
  114. package/test/code-preview.test.js +35 -0
  115. package/test/compare-ui-paths.test.js +24 -0
  116. package/test/compare.test.js +54 -0
  117. package/test/delete-trash.test.js +67 -0
  118. package/test/dirsize.test.js +138 -0
  119. package/test/file-ops.test.js +307 -0
  120. package/test/file-url.test.js +24 -0
  121. package/test/find-contents.test.js +161 -0
  122. package/test/find-input.test.js +66 -0
  123. package/test/fixtures/pele-parity.json +1006 -0
  124. package/test/highlight-launcher.test.js +35 -0
  125. package/test/html-preview.test.js +22 -0
  126. package/test/input.test.js +15 -0
  127. package/test/keymap.test.js +26 -0
  128. package/test/language-icons.test.js +36 -0
  129. package/test/launcher.test.js +51 -0
  130. package/test/manual-archive-here-ui.mjs +47 -0
  131. package/test/manual-code-scroll.mjs +28 -0
  132. package/test/manual-column-scroll.mjs +24 -0
  133. package/test/manual-compare-ui.mjs +20 -0
  134. package/test/manual-find-status.mjs +37 -0
  135. package/test/manual-folder-focus.mjs +63 -0
  136. package/test/manual-html-security.mjs +23 -0
  137. package/test/manual-html-ui.mjs +30 -0
  138. package/test/manual-syntax-preview.mjs +26 -0
  139. package/test/manual-terminal-lifecycle.mjs +42 -0
  140. package/test/manual-terminal-navigation.mjs +48 -0
  141. package/test/manual-terminal-ui.mjs +47 -0
  142. package/test/manual-trash-ui.mjs +86 -0
  143. package/test/markdown-diagrams.test.js +93 -0
  144. package/test/markdown-html.test.js +105 -0
  145. package/test/mathml.test.js +92 -0
  146. package/test/menu-transfer.test.js +57 -0
  147. package/test/office-preview.test.js +154 -0
  148. package/test/pele-parity.test.js +28 -0
  149. package/test/places.test.js +134 -0
  150. package/test/preview-keys.test.js +60 -0
  151. package/test/preview-language.test.js +22 -0
  152. package/test/status-filename.test.js +20 -0
  153. package/test/transfer-replace-merge.test.js +187 -0
  154. package/test/trash-address.test.js +23 -0
  155. package/test/trash-view.test.js +37 -0
  156. package/test/trashbrowse.test.js +135 -0
  157. package/ui/AboutFacts.qml +78 -0
  158. package/ui/ArchiveCards.qml +95 -0
  159. package/ui/ArchiveCompressDialog.qml +378 -0
  160. package/ui/ArchiveHereConfirm.qml +127 -0
  161. package/ui/ArchivePasswordDialog.qml +257 -0
  162. package/ui/Backend.qml +775 -0
  163. package/ui/BulkOldNames.qml +47 -0
  164. package/ui/BulkRenameDialog.qml +380 -0
  165. package/ui/CardFrame.qml +67 -0
  166. package/ui/CardScroll.qml +79 -0
  167. package/ui/CheckBox.qml +73 -0
  168. package/ui/ChromeBar.qml +360 -0
  169. package/ui/ChromeButton.qml +131 -0
  170. package/ui/ChromeModes.qml +43 -0
  171. package/ui/CodeLines.qml +256 -0
  172. package/ui/CodeRefusal.qml +52 -0
  173. package/ui/CollideConfirm.qml +147 -0
  174. package/ui/CollideHost.qml +167 -0
  175. package/ui/ColumnPane.qml +525 -0
  176. package/ui/ColumnRow.qml +380 -0
  177. package/ui/ColumnsArea.qml +594 -0
  178. package/ui/ColumnsLanding.qml +147 -0
  179. package/ui/CompareView.qml +321 -0
  180. package/ui/ContextMenu.qml +743 -0
  181. package/ui/ConvertDialog.qml +456 -0
  182. package/ui/CountedWorker.qml +7 -0
  183. package/ui/Crumb.qml +64 -0
  184. package/ui/CrumbDrop.qml +25 -0
  185. package/ui/CsvTable.qml +394 -0
  186. package/ui/CursorMark.qml +41 -0
  187. package/ui/DefaultClaim.qml +130 -0
  188. package/ui/DeviceLock.qml +47 -0
  189. package/ui/DeviceMounts.qml +540 -0
  190. package/ui/DialogButton.qml +150 -0
  191. package/ui/DialogField.qml +147 -0
  192. package/ui/DialogHeader.qml +31 -0
  193. package/ui/DialogScrim.qml +20 -0
  194. package/ui/DialogTitle.qml +37 -0
  195. package/ui/Divider.qml +9 -0
  196. package/ui/DropInto.qml +126 -0
  197. package/ui/DropTarget.qml +35 -0
  198. package/ui/DropboxMark.qml +60 -0
  199. package/ui/EmptyState.qml +150 -0
  200. package/ui/EscapeHint.qml +11 -0
  201. package/ui/FactsTable.qml +54 -0
  202. package/ui/FastScrollHandler.qml +476 -0
  203. package/ui/FatNamesConfirm.qml +157 -0
  204. package/ui/Favourites.qml +143 -0
  205. package/ui/FigureService.qml +120 -0
  206. package/ui/FileDrag.qml +267 -0
  207. package/ui/FilterStrip.qml +133 -0
  208. package/ui/FitMetrics.qml +22 -0
  209. package/ui/FlashDriveRows.qml +137 -0
  210. package/ui/FlashHost.qml +72 -0
  211. package/ui/FlashImageRow.qml +104 -0
  212. package/ui/FlashRunner.qml +119 -0
  213. package/ui/FlashStepRow.qml +172 -0
  214. package/ui/FlashStrip.qml +38 -0
  215. package/ui/FlashView.qml +397 -0
  216. package/ui/FleaMark.qml +88 -0
  217. package/ui/FlyoutFade.qml +23 -0
  218. package/ui/FontPane.qml +170 -0
  219. package/ui/Glass.qml +114 -0
  220. package/ui/GlassTagger.qml +59 -0
  221. package/ui/Glyph.qml +64 -0
  222. package/ui/GlyphSolid.qml +22 -0
  223. package/ui/GridArea.qml +664 -0
  224. package/ui/GridTile.qml +325 -0
  225. package/ui/GvfsBridge.qml +164 -0
  226. package/ui/Header.qml +433 -0
  227. package/ui/HoverTimers.qml +39 -0
  228. package/ui/HtmlClip.qml +30 -0
  229. package/ui/HtmlPane.qml +63 -0
  230. package/ui/HyprlandMark.qml +45 -0
  231. package/ui/Ipc.qml +1005 -0
  232. package/ui/IpcControls.qml +7 -0
  233. package/ui/IpcMenuState.qml +48 -0
  234. package/ui/IpcPreviewState.qml +185 -0
  235. package/ui/JumpPath.qml +51 -0
  236. package/ui/KeymapSheet.qml +561 -0
  237. package/ui/KeymapSheetResult.qml +89 -0
  238. package/ui/KindStack.qml +40 -0
  239. package/ui/LangMark.qml +51 -0
  240. package/ui/LangMarkLoader.qml +26 -0
  241. package/ui/List.qml +480 -0
  242. package/ui/LoadingState.qml +54 -0
  243. package/ui/LocalSend.qml +56 -0
  244. package/ui/LocalSendMark.qml +73 -0
  245. package/ui/MarkdownBlockView.qml +311 -0
  246. package/ui/MarkdownBlocks.qml +35 -0
  247. package/ui/MarkdownFigure.qml +254 -0
  248. package/ui/MarkdownImages.qml +72 -0
  249. package/ui/MarkdownList.qml +81 -0
  250. package/ui/MarkdownMathsText.qml +97 -0
  251. package/ui/MarkdownPane.qml +83 -0
  252. package/ui/MarkdownPictures.qml +41 -0
  253. package/ui/MarkdownQuote.qml +52 -0
  254. package/ui/MarkdownRemote.qml +82 -0
  255. package/ui/MarkdownSource.qml +155 -0
  256. package/ui/MarkdownTable.qml +222 -0
  257. package/ui/MarkdownTableScroll.qml +64 -0
  258. package/ui/MarkdownTableWheel.qml +126 -0
  259. package/ui/MarkdownText.qml +87 -0
  260. package/ui/MarkdownWorker.js +132 -0
  261. package/ui/MatchText.qml +99 -0
  262. package/ui/MediaSession.qml +38 -0
  263. package/ui/MediaSound.qml +26 -0
  264. package/ui/MediaStrip.qml +191 -0
  265. package/ui/MediaTrack.qml +36 -0
  266. package/ui/MediaVolume.qml +54 -0
  267. package/ui/MenuActionDialog.qml +396 -0
  268. package/ui/MenuEdgeFade.qml +24 -0
  269. package/ui/MenuHost.qml +227 -0
  270. package/ui/MenuRow.qml +351 -0
  271. package/ui/MountListing.qml +100 -0
  272. package/ui/NetworkDialog.qml +435 -0
  273. package/ui/NetworkForm.qml +426 -0
  274. package/ui/NetworkMounts.qml +913 -0
  275. package/ui/NetworkPlaces.qml +127 -0
  276. package/ui/OpenWithDialog.qml +613 -0
  277. package/ui/Opener.qml +95 -0
  278. package/ui/Pane.qml +1320 -0
  279. package/ui/PaneMenuActions.qml +527 -0
  280. package/ui/PanePath.qml +90 -0
  281. package/ui/PaneRail.qml +268 -0
  282. package/ui/PaneStates.qml +88 -0
  283. package/ui/PaneSwap.qml +339 -0
  284. package/ui/PaneWire.qml +601 -0
  285. package/ui/ParkedWait.qml +9 -0
  286. package/ui/PathEntry.qml +186 -0
  287. package/ui/PathJump.qml +400 -0
  288. package/ui/PdfViewer.qml +297 -0
  289. package/ui/PermissionsDialog.qml +658 -0
  290. package/ui/PermissionsHeadings.qml +31 -0
  291. package/ui/PhoneMounts.qml +67 -0
  292. package/ui/PickerAnswers.qml +75 -0
  293. package/ui/PickerBox.qml +26 -0
  294. package/ui/PickerChrome.qml +295 -0
  295. package/ui/PickerFilter.qml +97 -0
  296. package/ui/PickerGrid.qml +308 -0
  297. package/ui/PickerHeader.qml +28 -0
  298. package/ui/PickerLifecycle.qml +27 -0
  299. package/ui/PickerList.qml +218 -0
  300. package/ui/PickerListing.qml +149 -0
  301. package/ui/PickerPathBar.qml +127 -0
  302. package/ui/PickerPlaces.qml +189 -0
  303. package/ui/PickerRecent.qml +92 -0
  304. package/ui/PickerSave.qml +101 -0
  305. package/ui/PickerSelection.qml +155 -0
  306. package/ui/PickerWindow.qml +846 -0
  307. package/ui/PowerSectorsReader.qml +10 -0
  308. package/ui/PrebuildDriver.qml +146 -0
  309. package/ui/Preview.qml +1005 -0
  310. package/ui/PreviewAnimation.qml +24 -0
  311. package/ui/PreviewArchive.qml +91 -0
  312. package/ui/PreviewColumn.qml +553 -0
  313. package/ui/PreviewEdge.qml +63 -0
  314. package/ui/PreviewFacts.qml +30 -0
  315. package/ui/PreviewFactsLine.qml +34 -0
  316. package/ui/PreviewHtml.qml +233 -0
  317. package/ui/PreviewImage.qml +253 -0
  318. package/ui/PreviewImagePan.qml +13 -0
  319. package/ui/PreviewImageSharp.qml +32 -0
  320. package/ui/PreviewLines.qml +106 -0
  321. package/ui/PreviewMarkdown.qml +706 -0
  322. package/ui/PreviewMedia.qml +250 -0
  323. package/ui/PreviewPdf.qml +482 -0
  324. package/ui/PreviewScroll.qml +201 -0
  325. package/ui/PreviewSwap.qml +335 -0
  326. package/ui/PreviewText.qml +149 -0
  327. package/ui/ProtocolChip.qml +18 -0
  328. package/ui/QuickLookArchive.qml +41 -0
  329. package/ui/QuickLookBar.qml +103 -0
  330. package/ui/QuickLookPrepare.qml +355 -0
  331. package/ui/QuickLookSwap.qml +10 -0
  332. package/ui/QuickLookWarm.qml +65 -0
  333. package/ui/RailDrop.qml +155 -0
  334. package/ui/RailHeading.qml +19 -0
  335. package/ui/RailPlaces.qml +38 -0
  336. package/ui/RailTrashRow.qml +67 -0
  337. package/ui/RenameField.qml +353 -0
  338. package/ui/RendererRetry.qml +11 -0
  339. package/ui/ResizeHandle.qml +52 -0
  340. package/ui/Reveal.qml +54 -0
  341. package/ui/Row.qml +476 -0
  342. package/ui/RowDrag.qml +213 -0
  343. package/ui/RowDropTarget.qml +27 -0
  344. package/ui/RunCard.qml +286 -0
  345. package/ui/Scripts.qml +65 -0
  346. package/ui/SearchStrip.qml +232 -0
  347. package/ui/SelectionBand.qml +140 -0
  348. package/ui/SelectionPreview.qml +370 -0
  349. package/ui/SettingsFavourite.qml +122 -0
  350. package/ui/SettingsGroup.qml +96 -0
  351. package/ui/SettingsHint.qml +12 -0
  352. package/ui/SettingsMetrics.qml +29 -0
  353. package/ui/SettingsPane.qml +178 -0
  354. package/ui/SettingsPanel.qml +547 -0
  355. package/ui/SettingsRail.qml +128 -0
  356. package/ui/SettingsRow.qml +409 -0
  357. package/ui/SettingsRuler.qml +85 -0
  358. package/ui/SettingsSegment.qml +85 -0
  359. package/ui/ShareBrowser.qml +113 -0
  360. package/ui/ShareLink.qml +67 -0
  361. package/ui/ShelfPins.qml +101 -0
  362. package/ui/Sidebar.qml +728 -0
  363. package/ui/SidebarRow.qml +358 -0
  364. package/ui/Spinner.qml +60 -0
  365. package/ui/StableModel.qml +89 -0
  366. package/ui/StateMessage.qml +84 -0
  367. package/ui/StatusBar.qml +512 -0
  368. package/ui/StatusFileName.qml +27 -0
  369. package/ui/TabBar.qml +673 -0
  370. package/ui/TabDragGeometry.qml +60 -0
  371. package/ui/TagMenuMark.qml +52 -0
  372. package/ui/TagRailSection.qml +53 -0
  373. package/ui/TagSlot.qml +40 -0
  374. package/ui/TagState.qml +150 -0
  375. package/ui/TagSwatch.qml +28 -0
  376. package/ui/Taildrop.qml +86 -0
  377. package/ui/TailscaleMark.qml +50 -0
  378. package/ui/TerminalService.qml +69 -0
  379. package/ui/TerminalTab.qml +48 -0
  380. package/ui/TerminalTabs.qml +27 -0
  381. package/ui/Theme.qml +460 -0
  382. package/ui/ThemeColors.qml +43 -0
  383. package/ui/TransferCard.qml +239 -0
  384. package/ui/TrashConfirm.qml +129 -0
  385. package/ui/TrashDropHandler.qml +11 -0
  386. package/ui/TrashHost.qml +202 -0
  387. package/ui/TrashMonitor.qml +30 -0
  388. package/ui/TrashToolbar.qml +19 -0
  389. package/ui/TrashView.qml +492 -0
  390. package/ui/UnlockDialog.qml +450 -0
  391. package/ui/UnlockHost.qml +206 -0
  392. package/ui/UpdateCheck.qml +97 -0
  393. package/ui/UserDirs.qml +25 -0
  394. package/ui/ViewState.qml +565 -0
  395. package/ui/ViewportScrollBar.qml +195 -0
  396. package/ui/ViewportScrollBars.qml +25 -0
  397. package/ui/WebPreview.qml +33 -0
  398. package/ui/WebPreviewView.qml +26 -0
  399. package/ui/WindowBody.qml +829 -0
  400. package/ui/WindowDrag.qml +35 -0
  401. package/ui/boot/Commons/AudioNodes.qml +50 -0
  402. package/ui/boot/Commons/AudioNodesModel.js +96 -0
  403. package/ui/boot/Commons/Border.qml +243 -0
  404. package/ui/boot/Commons/BorderGeometry.js +373 -0
  405. package/ui/boot/Commons/Color.qml +258 -0
  406. package/ui/boot/Commons/I18n.qml +118 -0
  407. package/ui/boot/Commons/InputDevices.qml +112 -0
  408. package/ui/boot/Commons/InputMethodState.qml +38 -0
  409. package/ui/boot/Commons/IpcRegistry.qml +77 -0
  410. package/ui/boot/Commons/Numbers.js +19 -0
  411. package/ui/boot/Commons/Plural.js +91 -0
  412. package/ui/boot/Commons/ShellIpc.qml +12 -0
  413. package/ui/boot/Commons/Style.qml +561 -0
  414. package/ui/boot/Commons/Translations.qml +100 -0
  415. package/ui/boot/Commons/UntypedInput.qml +152 -0
  416. package/ui/boot/Commons/Util.qml +188 -0
  417. package/ui/boot/Commons/qmldir +13 -0
  418. package/ui/boot/LICENSE-omarchy +20 -0
  419. package/ui/boot/Ui/BackgroundMedia.qml +49 -0
  420. package/ui/boot/Ui/BarIconButton.qml +106 -0
  421. package/ui/boot/Ui/BarIconContent.qml +38 -0
  422. package/ui/boot/Ui/BarIndicator.qml +53 -0
  423. package/ui/boot/Ui/BarWidget.qml +50 -0
  424. package/ui/boot/Ui/BorderOverlay.qml +54 -0
  425. package/ui/boot/Ui/BorderSurface.qml +40 -0
  426. package/ui/boot/Ui/Button.qml +224 -0
  427. package/ui/boot/Ui/ButtonGroup.qml +131 -0
  428. package/ui/boot/Ui/ConfirmDialog.qml +134 -0
  429. package/ui/boot/Ui/CursorSurface.qml +42 -0
  430. package/ui/boot/Ui/Dropdown.qml +245 -0
  431. package/ui/boot/Ui/FilterInput.qml +26 -0
  432. package/ui/boot/Ui/IconContentBounds.qml +141 -0
  433. package/ui/boot/Ui/KeyboardPanel.qml +453 -0
  434. package/ui/boot/Ui/MultiSelect.qml +624 -0
  435. package/ui/boot/Ui/NumberField.qml +86 -0
  436. package/ui/boot/Ui/OpticalGlyph.qml +68 -0
  437. package/ui/boot/Ui/OverlayWindow.qml +102 -0
  438. package/ui/boot/Ui/Panel.qml +60 -0
  439. package/ui/boot/Ui/PanelActionButton.qml +105 -0
  440. package/ui/boot/Ui/PanelController.qml +16 -0
  441. package/ui/boot/Ui/PanelHero.qml +112 -0
  442. package/ui/boot/Ui/PanelKeyCatcher.qml +100 -0
  443. package/ui/boot/Ui/PanelSectionHeader.qml +31 -0
  444. package/ui/boot/Ui/PanelSeparator.qml +19 -0
  445. package/ui/boot/Ui/PanelSlider.qml +156 -0
  446. package/ui/boot/Ui/PanelToolTip.qml +50 -0
  447. package/ui/boot/Ui/PluginBarApi.qml +89 -0
  448. package/ui/boot/Ui/PointerMoveGate.qml +54 -0
  449. package/ui/boot/Ui/PopupCard.qml +181 -0
  450. package/ui/boot/Ui/ScreenMoveRemap.qml +43 -0
  451. package/ui/boot/Ui/SearchableDropdown.qml +354 -0
  452. package/ui/boot/Ui/SizedImage.qml +125 -0
  453. package/ui/boot/Ui/SpeedTestOverlay.qml +412 -0
  454. package/ui/boot/Ui/TextField.qml +58 -0
  455. package/ui/boot/Ui/Toggle.qml +118 -0
  456. package/ui/boot/Ui/ToggleSwitch.qml +115 -0
  457. package/ui/boot/Ui/WidgetButton.qml +172 -0
  458. package/ui/boot/Ui/qmldir +41 -0
  459. package/ui/boot/fleatab.qml +50 -0
  460. package/ui/boot/picker.qml +39 -0
  461. package/ui/boot/shell.qml +131 -0
  462. package/ui/boot/tabtearoff.qml +51 -0
  463. package/ui/js/Anchor.js +379 -0
  464. package/ui/js/AnchorHold.js +162 -0
  465. package/ui/js/Archive.js +157 -0
  466. package/ui/js/ArchiveCard.js +44 -0
  467. package/ui/js/ArchiveOps.js +44 -0
  468. package/ui/js/BackReturn.js +118 -0
  469. package/ui/js/BulkRename.js +100 -0
  470. package/ui/js/Buttons.js +54 -0
  471. package/ui/js/ChromeKeys.js +116 -0
  472. package/ui/js/ClipMarks.js +73 -0
  473. package/ui/js/ClipSelection.js +67 -0
  474. package/ui/js/Clipboard.js +179 -0
  475. package/ui/js/Cloud.js +97 -0
  476. package/ui/js/CodeRuns.js +72 -0
  477. package/ui/js/Collide.js +212 -0
  478. package/ui/js/ColumnFit.js +28 -0
  479. package/ui/js/ColumnMenu.js +111 -0
  480. package/ui/js/Columns.js +298 -0
  481. package/ui/js/ColumnsCarry.js +103 -0
  482. package/ui/js/Compare.js +74 -0
  483. package/ui/js/Contrast.js +157 -0
  484. package/ui/js/ControlReader.js +42 -0
  485. package/ui/js/Convert.js +52 -0
  486. package/ui/js/CopyAs.js +52 -0
  487. package/ui/js/Crumbs.js +178 -0
  488. package/ui/js/Csv.js +231 -0
  489. package/ui/js/Density.js +44 -0
  490. package/ui/js/Devices.js +440 -0
  491. package/ui/js/DirSizes.js +180 -0
  492. package/ui/js/Drag.js +360 -0
  493. package/ui/js/DragOut.js +166 -0
  494. package/ui/js/DropDev.js +52 -0
  495. package/ui/js/Dropbox.js +41 -0
  496. package/ui/js/Eject.js +217 -0
  497. package/ui/js/Errors.js +188 -0
  498. package/ui/js/ExtThumbs.js +115 -0
  499. package/ui/js/Facts.js +402 -0
  500. package/ui/js/FigureDate.js +14 -0
  501. package/ui/js/Filter.js +285 -0
  502. package/ui/js/Find.js +46 -0
  503. package/ui/js/Flash.js +184 -0
  504. package/ui/js/FlashCard.js +79 -0
  505. package/ui/js/FlashEndings.js +125 -0
  506. package/ui/js/FlashPane.js +116 -0
  507. package/ui/js/FleaBin.js +12 -0
  508. package/ui/js/Focus.js +504 -0
  509. package/ui/js/FolderSorts.js +108 -0
  510. package/ui/js/FolderViews.js +44 -0
  511. package/ui/js/Format.js +314 -0
  512. package/ui/js/Fuzzy.js +141 -0
  513. package/ui/js/GlassTag.js +72 -0
  514. package/ui/js/Grid.js +33 -0
  515. package/ui/js/GridGeometry.js +90 -0
  516. package/ui/js/GridNames.js +153 -0
  517. package/ui/js/GvfsBridge.js +200 -0
  518. package/ui/js/HostClipboard.js +29 -0
  519. package/ui/js/Icons.js +218 -0
  520. package/ui/js/Input.js +50 -0
  521. package/ui/js/Jump.js +200 -0
  522. package/ui/js/KeyName.js +64 -0
  523. package/ui/js/Keymap.js +401 -0
  524. package/ui/js/Kinds.js +164 -0
  525. package/ui/js/LICENSES/ISC-lucide.txt +43 -0
  526. package/ui/js/LangMarkPaths.js +47 -0
  527. package/ui/js/LangMarks.js +120 -0
  528. package/ui/js/Lists.js +11 -0
  529. package/ui/js/LocalSend.js +39 -0
  530. package/ui/js/LockedMenu.js +63 -0
  531. package/ui/js/MakeDefault.js +186 -0
  532. package/ui/js/MarkBox.js +7 -0
  533. package/ui/js/Markdown.js +119 -0
  534. package/ui/js/MarkdownLists.js +86 -0
  535. package/ui/js/MarkdownMaths.js +58 -0
  536. package/ui/js/MarkdownPictures.js +32 -0
  537. package/ui/js/MarkdownPrepared.js +139 -0
  538. package/ui/js/MarkdownTableFit.js +34 -0
  539. package/ui/js/Marks.js +148 -0
  540. package/ui/js/Marquee.js +96 -0
  541. package/ui/js/Match.js +93 -0
  542. package/ui/js/Material.js +109 -0
  543. package/ui/js/MdBlocks.js +437 -0
  544. package/ui/js/MdBreak.js +71 -0
  545. package/ui/js/MdChunks.js +70 -0
  546. package/ui/js/MdContainer.js +137 -0
  547. package/ui/js/MdDocument.js +337 -0
  548. package/ui/js/MdEmph.js +97 -0
  549. package/ui/js/MdEntity.js +108 -0
  550. package/ui/js/MdEntityTable.js +223 -0
  551. package/ui/js/MdEscape.js +59 -0
  552. package/ui/js/MdFront.js +37 -0
  553. package/ui/js/MdHold.js +32 -0
  554. package/ui/js/MdHtml.js +307 -0
  555. package/ui/js/MdHtmlBlock.js +290 -0
  556. package/ui/js/MdHtmlHeading.js +53 -0
  557. package/ui/js/MdHtmlImage.js +179 -0
  558. package/ui/js/MdInline.js +154 -0
  559. package/ui/js/MdItems.js +212 -0
  560. package/ui/js/MdLeaf.js +309 -0
  561. package/ui/js/MdLink.js +196 -0
  562. package/ui/js/MdMath.js +67 -0
  563. package/ui/js/MdParagraphs.js +138 -0
  564. package/ui/js/MdRefs.js +232 -0
  565. package/ui/js/MdResolve.js +226 -0
  566. package/ui/js/MdRun.js +300 -0
  567. package/ui/js/MdUrl.js +226 -0
  568. package/ui/js/Menu.js +514 -0
  569. package/ui/js/MenuContext.js +85 -0
  570. package/ui/js/MenuFit.js +13 -0
  571. package/ui/js/MenuRefresh.js +74 -0
  572. package/ui/js/MenuWheel.js +35 -0
  573. package/ui/js/Messages.js +186 -0
  574. package/ui/js/Motion.js +16 -0
  575. package/ui/js/Mounts.js +320 -0
  576. package/ui/js/MouseNav.js +13 -0
  577. package/ui/js/Nav.js +329 -0
  578. package/ui/js/NetFs.js +26 -0
  579. package/ui/js/OpenWith.js +83 -0
  580. package/ui/js/Ops.js +585 -0
  581. package/ui/js/Palette.js +33 -0
  582. package/ui/js/PathBar.js +260 -0
  583. package/ui/js/Permissions.js +179 -0
  584. package/ui/js/Phones.js +112 -0
  585. package/ui/js/Picker.js +353 -0
  586. package/ui/js/PlaceMenu.js +96 -0
  587. package/ui/js/Places.js +265 -0
  588. package/ui/js/PreviewAsk.js +21 -0
  589. package/ui/js/PreviewKeys.js +155 -0
  590. package/ui/js/PreviewSettle.js +29 -0
  591. package/ui/js/PreviewSwap.js +101 -0
  592. package/ui/js/PropertyFacts.js +144 -0
  593. package/ui/js/Protocols.js +296 -0
  594. package/ui/js/QuickLookKinds.js +27 -0
  595. package/ui/js/QuickLookRect.js +24 -0
  596. package/ui/js/RailDrop.js +51 -0
  597. package/ui/js/RailKeys.js +87 -0
  598. package/ui/js/RailMenu.js +133 -0
  599. package/ui/js/Recent.js +135 -0
  600. package/ui/js/RecentMode.js +156 -0
  601. package/ui/js/Reload.js +60 -0
  602. package/ui/js/Renderer.js +9 -0
  603. package/ui/js/RunFile.js +143 -0
  604. package/ui/js/Scripts.js +28 -0
  605. package/ui/js/Scroll.js +304 -0
  606. package/ui/js/ScrollOff.js +69 -0
  607. package/ui/js/Search.js +478 -0
  608. package/ui/js/Selection.js +97 -0
  609. package/ui/js/Settings.js +476 -0
  610. package/ui/js/SettingsAbout.js +97 -0
  611. package/ui/js/SettingsShelf.js +52 -0
  612. package/ui/js/SheetKeys.js +42 -0
  613. package/ui/js/SheetQuery.js +281 -0
  614. package/ui/js/ShelfPile.js +27 -0
  615. package/ui/js/SlowClick.js +53 -0
  616. package/ui/js/SlowOp.js +6 -0
  617. package/ui/js/Sort.js +134 -0
  618. package/ui/js/Startup.js +63 -0
  619. package/ui/js/StateWords.js +17 -0
  620. package/ui/js/Status.js +238 -0
  621. package/ui/js/Swap.js +166 -0
  622. package/ui/js/TabMove.js +39 -0
  623. package/ui/js/Tabs.js +751 -0
  624. package/ui/js/Tags.js +134 -0
  625. package/ui/js/Taildrop.js +128 -0
  626. package/ui/js/Tap.js +180 -0
  627. package/ui/js/TextSize.js +107 -0
  628. package/ui/js/Thumbs.js +158 -0
  629. package/ui/js/Transfer.js +172 -0
  630. package/ui/js/Trash.js +84 -0
  631. package/ui/js/TrashDates.js +47 -0
  632. package/ui/js/TrashDrop.js +64 -0
  633. package/ui/js/UiState.js +438 -0
  634. package/ui/js/Unlock.js +152 -0
  635. package/ui/js/Update.js +130 -0
  636. package/ui/js/UserDirs.js +56 -0
  637. package/ui/qmldir +230 -0
@@ -0,0 +1,664 @@
1
+ import QtQuick
2
+ import "." as Flea
3
+ import "js/ClipMarks.js" as ClipMarks
4
+ import "js/Density.js" as Density
5
+ import "js/DirSizes.js" as DirSizes
6
+ import "js/Drag.js" as DragOps
7
+ import "js/DragOut.js" as DragOut
8
+ import "js/ExtThumbs.js" as ExtThumbs
9
+ import "js/Filter.js" as Filter
10
+ import "js/Focus.js" as Focus
11
+ import "js/GridGeometry.js" as GridGeometry
12
+ import "js/Scroll.js" as Scroll
13
+ import "js/Tap.js" as Tap
14
+ import "js/Thumbs.js" as Thumbs
15
+
16
+ // Grid shares the list's rows, marks, thumbnails and viewport plan, scaled to tile rows.
17
+ GridView {
18
+ id: root
19
+
20
+ property var pane: null
21
+ readonly property bool fileDragActive: dragSession.Drag.active
22
+ property var menu: null
23
+
24
+ property real zoomTravel: 0
25
+ readonly property int wheelNotch: 120
26
+ readonly property int touchpadStep: 48
27
+
28
+ function zoomWheel(wheel) {
29
+ if (!ViewState.ctrlZoom) return false
30
+ var phase = wheel.phase !== undefined ? wheel.phase : Qt.NoScrollPhase
31
+ root.zoomTravel += Scroll.zoomTravel(phase, wheel.pixelDelta.y, wheel.angleDelta.y, root.touchpadStep, root.wheelNotch)
32
+ var steps = root.zoomTravel > 0 ? Math.floor(root.zoomTravel) : Math.ceil(root.zoomTravel)
33
+ if (steps !== 0) {
34
+ root.zoomTravel -= steps
35
+ var sizes = ["small", "medium", "large", "xlarge", "huge", "largest"]
36
+ var next = Math.max(0, Math.min(sizes.length - 1, sizes.indexOf(ViewState.thumbnailSize) + steps))
37
+ ViewState.changeSetting("preview.thumbSize", sizes[next])
38
+ }
39
+ return true
40
+ }
41
+
42
+ signal thumbsApplied(var work)
43
+ signal dirSizesApplied(var ask)
44
+ signal dirSizesCancelled()
45
+
46
+ // Tile columns leave one gap, both edge insets and the scroll lane.
47
+ readonly property int columns: GridGeometry.columnsFor(root.width, Theme.grid.minCellWidth,
48
+ ViewState.thumbnailPixels, Theme.spacing.rowPaddingX, Theme.spacing.gap, Theme.spacing.rowPaddingX)
49
+ readonly property int tileRows: Math.max(1, Math.ceil(root.pane.shownTotal / root.columns))
50
+ // Mark, one gap, two caption lines, and the density's pad above and below.
51
+ readonly property int cellHeightPx: GridGeometry.cellHeightFor(ViewState.thumbnailPixels, Theme.spacing.gap,
52
+ Math.ceil(Theme.grid.captionHeight),
53
+ Density.gridPadY(Theme.spacing.rowPaddingX, ViewState.density))
54
+ + renameExtraHeight
55
+ property Item renameEditor: null
56
+ property real renameExtraHeight: 0
57
+ property var renameRetirement: null
58
+
59
+ // Grid pooling can leave itemAtIndex pointing at a superseded same-row tile.
60
+ function currentRenameTile(expectedPane) {
61
+ var editor = root.renameEditor
62
+ var host = editor ? editor.editorHost : null
63
+ return editor && editor.visible && root.visible && !root.hiddenHeld && host && host.visible
64
+ && editor.pane === expectedPane && editor.viewport === root && editor.ownsEdit()
65
+ && host === editor.layoutHost() && host.renaming && host.editorField === editor ? host : null
66
+ }
67
+
68
+ onPaneChanged: { root.renameRetirement = null; root.queueRenameLayout(); root.takeHeld() }
69
+ // Editor replacement and destruction must not reenter Grid layout through its cell height.
70
+ onRenameEditorChanged: {
71
+ if (root.renameEditor) root.renameRetirement = null
72
+ root.queueRenameLayout()
73
+ }
74
+ function queueRenameLayout() { Qt.callLater(root.settleRenameEditor) }
75
+ function retireRenameEditor(editor, retirement) {
76
+ if (root.renameEditor !== editor) return
77
+ root.renameRetirement = retirement
78
+ root.renameEditor = null
79
+ }
80
+ function settleRenameEditor() {
81
+ var retirement = root.renameRetirement
82
+ var sameEdit = retirement && !root.renameEditor && root.pane && root.pane === retirement.pane
83
+ && root === retirement.viewport && root.pane.renamingIndex === retirement.index
84
+ var row = sameEdit ? root.pane.rowFor(retirement.index) : null
85
+ // A pending write can outlive its Loader. Keep only its values until that exact edit returns.
86
+ var keep = sameEdit && row && row.n.split("/").pop() === retirement.name
87
+ && root.pane.renamePending && root.pane.renameRequest === retirement.request
88
+ if (!keep) root.renameRetirement = null
89
+ if (sameEdit && !root.pane.renamePending)
90
+ root.pane.renamingIndex = -1
91
+ var editor = root.renameEditor
92
+ if (editor && root.pane && root.pane.renamingIndex >= 0 && editor.extraHeight < 0) return
93
+ var height = root.pane && root.pane.renamingIndex >= 0 && editor ? editor.extraHeight : 0
94
+ if (height === root.renameExtraHeight) return
95
+ if (editor) editor.queueContainment()
96
+ root.renameExtraHeight = height
97
+ }
98
+ readonly property int visibleTileRows: Math.max(1, Math.ceil(root.height / root.cellHeightPx))
99
+ onColumnsChanged: if (root.visible) { settle.restart(); coalesce.restart() }
100
+ onVisibleTileRowsChanged: if (root.visible) { settle.restart(); coalesce.restart() }
101
+
102
+ focus: true
103
+ // Whichever view is up owns the keyboard, and Focus.handleKey is the one route all three take.
104
+ Keys.onPressed: function (event) {
105
+ root.prebuild.kick()
106
+ root.holdCache()
107
+ event.accepted = Focus.handleKey(event, root.pane, root.pane.sidebar)
108
+ }
109
+ // Written, not bound: a count change puts the view on row 0 as a reset does, which would drop a binding.
110
+ readonly property int cursorView: Filter.viewOf(root.pane.shown, root.pane.renamingIndex >= 0 ? root.pane.renamingIndex : root.pane.cursorIndex)
111
+ onCursorViewChanged: { root.prebuild.kick(); root.askLanding(); root.currentIndex = root.cursorView }
112
+ // Hidden holds no delegates; an edit in flight keeps its own per RenameField.qml.
113
+ model: Flea.StableModel { view: root; total: (root.visible || root.pane.renamingIndex >= 0) ? root.pane.shownTotal : 0; onResized: root.modelResized(); holdCurrent: root.pane.renamingIndex >= 0
114
+ warm: root.visible && root.pane.searchMode.length > 0 && root.pane.swap.searchWarm === true; warmRows: root.columns * (Math.floor(Math.max(0, root.height - root.topMargin + root.cacheFull) / root.cellHeight) + 2) }
115
+ clip: true
116
+ // Qt's own tracking scrolls a flush-parked end to the footer's end on a cursor move; revealCursor's Contain leaves a whole tile alone.
117
+ highlightFollowsCurrentItem: false
118
+ // Qt emits currentIndexChanged before it frees the old current item; positioning inside it leaves that item behind as a second delegate for its row.
119
+ onCurrentIndexChanged: { root.prebuild.kick(); root.holdCache(); Qt.callLater(root.revealCursor) }
120
+ function revealCursor() {
121
+ // StableModel.resize parks currentIndex on row 0 mid-change, so onResized places the view; a far landing waits for its window, which onRowsChanged lands.
122
+ if (root.visible && !root.hiddenHeld && !root.landingWait && root.count > 0 && root.cursorView >= 0 && root.currentIndex === root.cursorView)
123
+ root.containTile(root.cursorView)
124
+ }
125
+ // One gap of bare ground along the left, the top and below the last row; the hairline inset stays.
126
+ leftMargin: Theme.spacing.gap
127
+ topMargin: Theme.spacing.gap
128
+ bottomMargin: Theme.spacing.gap
129
+ cellWidth: GridGeometry.cellWidthFor(root.width, root.columns, Theme.spacing.gap, Theme.spacing.rowPaddingX)
130
+ cellHeight: root.cellHeightPx
131
+ // An emptied view drops its cache rows; they come back in cacheStepsMargin frame steps, each built in its own turn, never by incubation an emptied view would cancel.
132
+ // A switch builds the viewport's tiles before its first frame and the rows past them after it, as every landing does.
133
+ readonly property int cacheFull: root.cellHeightPx * GridGeometry.cacheRows
134
+ property int cacheSteps: 0
135
+ readonly property int cacheStepsMargin: 4
136
+ property int cacheQuiet: 0
137
+ // The frames a key holds growth quiet, so the key's own frame builds nothing else.
138
+ readonly property int cacheQuietFrames: 2
139
+ cacheBuffer: root.cacheSteps > root.cacheStepsMargin ? root.cacheFull : 0
140
+ displayMarginEnd: root.cacheSteps > root.cacheStepsMargin ? 0 : root.cacheFull * root.cacheSteps / root.cacheStepsMargin
141
+ function regrowCache() {
142
+ if (root.model.count === 0)
143
+ root.cacheSteps = 0
144
+ cacheGrow.stop()
145
+ if (root.model.count > 0 && root.cacheSteps <= root.cacheStepsMargin)
146
+ cacheGrow.start()
147
+ }
148
+ function holdCache() {
149
+ if (cacheGrow.running) root.cacheQuiet = root.cacheQuietFrames
150
+ }
151
+ FrameAnimation {
152
+ id: cacheGrow
153
+ running: false
154
+ onTriggered: {
155
+ if (root.cacheQuiet > 0) root.cacheQuiet -= 1
156
+ if (root.cacheQuiet > 0 || root.pane.listInFlight || root.moving) return
157
+ root.cacheSteps += 1
158
+ root.forceLayout()
159
+ if (root.cacheSteps > root.cacheStepsMargin) cacheGrow.stop()
160
+ }
161
+ }
162
+ boundsBehavior: Flickable.StopAtBounds
163
+ reuseItems: true
164
+ // Parked tiles for the next landing: a tile parks unparented and the landing's layout parents it again.
165
+ readonly property Flea.PrebuildDriver prebuild: Flea.PrebuildDriver {
166
+ view: root
167
+ model: root.model
168
+ pane: root.pane
169
+ limit: root.landingTiles
170
+ held: root.hiddenHeld
171
+ rowsPerTick: 4
172
+ park: function (cell) { cell.pooled = true; cell.parent = null }
173
+ adopt: function (cell) { cell.pooled = false; cursorMark.place(cell) }
174
+ }
175
+ // The tiles a full landing from the top lays out; the partial row warmRows bounds stays out (Qt 6.11.2 qquickgridview.cpp:507).
176
+ readonly property int landingTiles: {
177
+ var c = root.columns, h = root.cellHeight, end = root.height - root.topMargin + root.cacheFull, n = 0
178
+ while (c > 0 && h > 0 && n < root.model.warmRows && Math.floor(n / c) * h <= end + h * (c - n % c) / (c + 1)) n++
179
+ return n
180
+ }
181
+ // The one tile drawn as the cursor; a cursor move touches two delegates, not every live one.
182
+ Flea.CursorMark { id: cursorMark; row: root.pane.cursorIndex }
183
+
184
+ Flea.FastScrollHandler {
185
+ parent: root
186
+ flickable: root
187
+ ctrlWheelAction: function (wheel) { return root.zoomWheel(wheel) }
188
+ onWheeled: root.endLanding(false)
189
+ }
190
+ // movementStarted is the view's own drag or flick, never a positionViewAtIndex or contentY write, so the landing's moves do not end its wait.
191
+ onMovementStarted: root.endLanding(false)
192
+
193
+ readonly property alias scrollBar: verticalScroll
194
+ Flea.ViewportScrollBar {
195
+ id: verticalScroll
196
+ parent: root
197
+ anchors { top: parent.top; right: parent.right }
198
+ flickable: root
199
+ ctrlWheelAction: function (wheel) { return root.zoomWheel(wheel) }
200
+ onUserScrolled: root.endLanding(false)
201
+ }
202
+
203
+ Flea.SelectionBand {
204
+ parent: root
205
+ pane: root.pane
206
+ flickable: root
207
+ columns: root.columns
208
+ cellWidth: root.cellWidth
209
+ cellHeight: root.cellHeight
210
+ rowAt: root.tileAt
211
+ }
212
+
213
+ Flea.FileDrag {
214
+ id: dragSession
215
+ pane: root.pane
216
+ }
217
+
218
+ delegate: Flea.GridTile {
219
+ id: cell
220
+ required property int index
221
+
222
+ // Acts on the backend row it displays; while pooled (GridTile.live) each listing read keeps its last value until onReused.
223
+ readonly property int listingIndex: cell.live ? Filter.at(root.pane.shown, index) : -1
224
+ // Filed by listing row in the view's cursor mark, which sets cursor; see ui/CursorMark.qml.
225
+ property int markRow: -1
226
+ // Built ahead of a landing past the shown rows: parked and unparented until the landing adopts it.
227
+ property bool prebuilt: false
228
+ // Where hover, a press, a tap or a drag reaches this tile: its icon box and painted caption.
229
+ readonly property QtObject pressMask: QtObject { function contains(point: point): bool { return root.hitsTile(cell, point) } }
230
+ readonly property Item rowDrag: rowDragItem
231
+ Component.onCompleted: if (!root.prebuild.built(cell)) cursorMark.place(cell)
232
+ Component.onDestruction: root.prebuild.gone(cell)
233
+ onParentChanged: if (cell.prebuilt && cell.parent === root.contentItem) root.prebuild.adoptCell(cell)
234
+ onListingIndexChanged: cursorMark.place(cell)
235
+ width: root.cellWidth
236
+ height: root.cellHeight
237
+ row: cell.live ? GridGeometry.heldRow(cell.rowMemo, root.heldRows, listingIndex) : cell.row
238
+ // One shared hover index for every tile, so no tile builds its own handler.
239
+ hovered: cell.live && root.hoveredIndex === cell.index
240
+ hoverShown: root.pane.selectionBand === null
241
+ selected: cell.live && root.pane.isSelected(listingIndex)
242
+ dropTarget: dragSession.dropIndex >= 0 && listingIndex === dragSession.dropIndex
243
+ dropCopying: dragSession.dragCopy
244
+ dropLinking: dragSession.dragLink
245
+ thumb: !cell.live ? cell.thumb : Thumbs.allowed(row, ViewState.thumbnailMode) ? Thumbs.fileFor(root.pane.thumbState, listingIndex) : ""
246
+ // List's own query and arming (ui/List.qml), so a tile marks what a row marks and builds its mark with the strip.
247
+ // flea-qml: a standing filter marks its own match, over Find's results too.
248
+ markQuery: root.pane.filterQuery.length > 0 ? root.pane.filterQuery : root.pane.searchMode.length > 0 ? root.pane.swap.answeredQuery : ""
249
+ markArmed: root.pane.filterTyping || root.pane.filterQuery.length > 0 || root.pane.searchMode.length > 0
250
+ renaming: listingIndex >= 0 && listingIndex === root.pane.renamingIndex
251
+ renamePane: root.pane
252
+ // The clipboard mark is looked up only for tiles a delegate holds.
253
+ clipMark: cell.live ? ClipMarks.markForRow(root.pane, cell.row ? cell.row.n : "", root.pane.clipboard) : cell.clipMark
254
+ onRenameCommitted: function(newName) { root.pane.commitRename(newName) }
255
+ onRenameAbandoned: root.pane.renamingIndex = -1
256
+
257
+ Item {
258
+ anchors.fill: parent
259
+ containmentMask: cell.pressMask
260
+ TapHandler {
261
+ id: tap
262
+ enabled: !cell.renaming
263
+ acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
264
+ // A held press must still tap on release.
265
+ longPressThreshold: 0
266
+ // A press held past the interval must not fire while the button is
267
+ // still down on a row about to be dragged; the release still arms.
268
+ onPressedChanged: if (pressed) root.pane.pressSlowClick()
269
+ onTapped: function (eventPoint, button) {
270
+ if (cell.listingIndex < 0) return
271
+ if (button === Qt.MiddleButton)
272
+ Tap.tappedTab(root.pane.rowFor(cell.listingIndex), root.pane.path, root.pane)
273
+ else if (button === Qt.RightButton)
274
+ Tap.tappedMenu(cell.listingIndex, eventPoint, root.pane, root.menu)
275
+ else {
276
+ var wasSole = root.pane.slowClickWasSole(cell.listingIndex)
277
+ Tap.tapped(cell.listingIndex, tap.tapCount, tap.point.modifiers, root.pane)
278
+ // The slow click renames on the pane's timer; a double click opens through tapped() above instead.
279
+ if (tap.tapCount === 2) root.pane.cancelSlowClick()
280
+ else if (tap.tapCount === 1 && Tap.onName(cell.captionItem, cell, eventPoint.position, true)) root.pane.armSlowClick(cell.listingIndex, tap.point.modifiers, dragSession.Drag.active, wasSole)
281
+ else root.pane.cancelSlowClick()
282
+ }
283
+ }
284
+ }
285
+ }
286
+
287
+ Flea.RowDrag {
288
+ id: rowDragItem
289
+ containmentMask: cell.pressMask
290
+ session: dragSession
291
+ listingIndex: cell.listingIndex
292
+ row: cell.row
293
+ // Drops answer from the one shared area below, so no tile builds its own.
294
+ dropsLocal: false
295
+ }
296
+ }
297
+
298
+ // One hover index for every tile: a per-tile HoverHandler costs a delegate each in the landing turn.
299
+ property int hoveredIndex: -1
300
+ // The tile under a view point, or -1 on a cell's bare margin or past the tiles: only the icon box and the caption hover.
301
+ function hoverAt(x, y) {
302
+ root.hoveredIndex = root.tileAt(x + root.contentX, y + root.contentY)
303
+ }
304
+ // A Flickable puts its handlers in the content item, so the probe's point is read from the scene, which a scroll leaves in place.
305
+ function hoverScene(scene) {
306
+ var p = root.mapFromItem(null, scene.x, scene.y)
307
+ root.hoverAt(p.x, p.y)
308
+ }
309
+ HoverHandler {
310
+ id: hoverProbe
311
+ enabled: root.visible && !root.hiddenHeld
312
+ onHoveredChanged: { if (!hovered) root.hoveredIndex = -1; else root.hoverScene(point.scenePosition) }
313
+ onPointChanged: if (hovered) root.hoverScene(point.scenePosition)
314
+ }
315
+ // One drop area for every folder tile: a per-tile DropArea costs a delegate each in the landing turn.
316
+ property var dropTile: null
317
+ property int dropListingIndex: -1
318
+ // What the tile under the drag answered; one refusal on entry must not end the area's events, so the area itself stays accepted and each move re-says this.
319
+ property bool dropAccepted: false
320
+ // A folder tile's drop row under a view point, or null on a file, past its icon and caption, or on bare ground; the index lookup never meets another item of the content, and a pooled or stale tile never answers.
321
+ function tileDropAt(x, y) {
322
+ var p = root.mapToItem(root.contentItem, x, y)
323
+ var tile = root.itemAtIndex(root.indexAt(p.x, p.y))
324
+ if (!tile || tile.visible === false || !tile.live || tile.listingIndex === undefined || tile.listingIndex < 0
325
+ || !tile.row || tile.row.d !== true || !root.hitsTile(tile, tile.mapFromItem(root, x, y)))
326
+ return null
327
+ return tile.rowDrag
328
+ }
329
+ // The hovered tile's own exit, or its record on the session when a re-list destroyed it already.
330
+ function dropLeft() {
331
+ var tile = root.dropTile
332
+ root.dropTile = null
333
+ root.dropListingIndex = -1
334
+ if (tile) {
335
+ tile.leaveAt()
336
+ return
337
+ }
338
+ dragSession.dropIndex = -1
339
+ dragSession.dropDest = ""
340
+ dragSession.dropDestDev = 0
341
+ dragSession.leaveTarget()
342
+ if (dragSession.dragRows.length === 0) {
343
+ dragSession.dragCopy = false
344
+ dragSession.dragLink = false
345
+ }
346
+ dragSession.hoverEnded()
347
+ DragOut.keys.leave()
348
+ }
349
+ function dropEnter(next, drag) {
350
+ root.dropTile = next
351
+ root.dropListingIndex = next ? next.listingIndex : -1
352
+ if (next) next.enterAt(drag, next.mapFromItem(root, drag.x, drag.y))
353
+ else drag.accepted = false
354
+ root.dropAccepted = drag.accepted
355
+ }
356
+ DropArea {
357
+ parent: root
358
+ anchors.fill: parent
359
+ // Bare ground and file tiles are not this area's, so the pane's floor (ui/PaneWire.qml) takes them as it does under List.
360
+ containmentMask: QtObject { function contains(point: point): bool { return root.tileDropAt(point.x, point.y) !== null } }
361
+ enabled: root.pane !== null && !root.pane.listInFlight
362
+ keys: [DragOps.ROWS_MIME, "text/uri-list", "text/plain"]
363
+ onEntered: function (drag) {
364
+ root.dropEnter(root.tileDropAt(drag.x, drag.y), drag)
365
+ drag.accepted = true
366
+ }
367
+ onPositionChanged: function (drag) {
368
+ var next = root.tileDropAt(drag.x, drag.y)
369
+ if (next !== root.dropTile || (next && next.listingIndex !== root.dropListingIndex)) {
370
+ if (root.dropTile || root.dropListingIndex >= 0) root.dropLeft()
371
+ root.dropEnter(next, drag)
372
+ } else {
373
+ if (next) next.moveAt(next.mapFromItem(root, drag.x, drag.y))
374
+ drag.accepted = root.dropAccepted
375
+ }
376
+ }
377
+ onExited: root.dropLeft()
378
+ onDropped: function (drop) {
379
+ var target = root.tileDropAt(drop.x, drop.y)
380
+ if (target !== root.dropTile) root.dropLeft()
381
+ root.dropTile = null
382
+ root.dropListingIndex = -1
383
+ if (target) target.dropAt(drop)
384
+ }
385
+ }
386
+
387
+ // One tile row of bare ground at the end, the same inset ui/List.qml keeps and for the same two
388
+ // reasons: a band has to start somewhere and the background menu has to be raisable at the end.
389
+ footer: Item {
390
+ width: Math.max(0, root.width - Theme.spacing.rowPaddingX)
391
+ height: Theme.chromeHeight
392
+ }
393
+
394
+ // The space past the last tile is the directory's own, the same rule ui/List.qml carries: a
395
+ // tile's right click belongs to its delegate, and tileAt is what tells the two apart.
396
+ TapHandler {
397
+ acceptedButtons: Qt.RightButton
398
+ onTapped: function (eventPoint) {
399
+ if (root.tileAt(eventPoint.position.x, eventPoint.position.y) < 0)
400
+ root.menu.openBackground(eventPoint.scenePosition)
401
+ }
402
+ }
403
+
404
+ // A tile is its icon box and its painted caption, or the whole editor while it renames; the rest of a cell is bare ground.
405
+ function hitsTile(tile, point) {
406
+ var icon = tile.thumbItem.mapFromItem(tile, point.x, point.y)
407
+ return tile.editing || (icon.x >= 0 && icon.x < tile.thumbItem.width && icon.y >= 0 && icon.y < tile.thumbItem.height)
408
+ || Tap.onName(tile.captionItem, tile, point, true)
409
+ }
410
+ // The tile index under a content point, -1 on a cell's bare margin or past the last tile.
411
+ function tileAt(x, y) {
412
+ var index = root.indexAt(x, y), tile = root.itemAtIndex(index)
413
+ return tile && root.hitsTile(tile, Qt.point(x - tile.x, y - tile.y)) ? index : -1
414
+ }
415
+
416
+ onContentYChanged: {
417
+ // Hidden geometry and a restore in flight move no shared state.
418
+ if (!root.visible || root.hiddenHeld)
419
+ return
420
+ // A scroll under a resting pointer moves the hovered tile without a point change.
421
+ if (hoverProbe.hovered) root.hoverScene(hoverProbe.point.scenePosition)
422
+ root.menu.close()
423
+ // A scroll never cancels a size the user asked for (src/dirsize.js).
424
+ coalesce.start()
425
+ settle.restart()
426
+ }
427
+
428
+ // The same drift check the list runs: a grid scrolled past the held window would otherwise draw
429
+ // empty tiles for rows the backend has never been asked for.
430
+ Timer {
431
+ id: coalesce
432
+ interval: root.pane.coalesceMs
433
+ repeat: false
434
+ onTriggered: root.requestIfDrifted()
435
+ }
436
+
437
+ Timer {
438
+ id: settle
439
+ interval: root.pane.settleMs
440
+ repeat: false
441
+ onTriggered: { root.requestThumbs(); root.requestDirSizes() }
442
+ }
443
+
444
+ function restartSettle() { settle.restart() }
445
+ function restartCoalesce() { coalesce.restart() }
446
+ function primeSettle() { settle.interval = root.pane.firstSettleMs }
447
+
448
+ Component.onCompleted: root.takeHeld()
449
+ // The held rows as the tiles read them, taken once per rows write: held and rows land as two writes, and a tile bound to both would read the old rows against the new start.
450
+ property var heldRows: ({ start: 0, rows: [], listing: 0 })
451
+ function takeHeld() { if (root.pane) root.heldRows = { start: root.pane.held, rows: root.pane.rows, listing: root.pane.backend ? root.pane.backend.heldListing : 0 } }
452
+ // The held window in tile rows, where Pane's windowSize and buffer count list rows: the list's context in pixels, rebuilt in tiles.
453
+ readonly property var windowPlan: GridGeometry.windowFor(root.columns, root.visibleTileRows, root.pane.buffer, Theme.fileRowHeight, root.cellHeightPx, root.pane.refetchMargin)
454
+ // A cursor landing past the held rows asks for its window now, ahead of the move Pane.showRow makes right after, so the first layout binds real rows.
455
+ function askLanding() {
456
+ if (root.cursorView < 0 || root.hiddenHeld) return
457
+ var need = root.landingNeed()
458
+ // Set before the ask: a reply that beats this call lands the view in onRowsChanged.
459
+ root.landingWait = need !== null && root.owes()
460
+ root.landingStart = need === null ? -1 : need.start
461
+ root.askWindow(need)
462
+ }
463
+ // The window a far cursor landing owes, null for a step, a landing the held rows reach, or a view that may not ask.
464
+ function landingNeed() {
465
+ return GridGeometry.landingAsk(root.windowPlan, root.cursorView, root.visibleRange().first, root.pane.total, root.pane.held, root.pane.rows.length)
466
+ }
467
+ // Owed while the cursor's own row is not held; a landing inside the held rows has rows to bind and moves at once.
468
+ function owes() { return root.canAsk() && root.pane.rowFor(root.pane.cursorIndex) === null }
469
+ function windowOwed() { return root.owes() && root.landingNeed() !== null }
470
+ // The view move of a cursor landing, which Pane.showRow makes right after the ask: a far one waits for its rows, as one pass binds them where two would clear then bind.
471
+ function showCursor(view, context) {
472
+ if (!root.landingWait) root.containTile(view)
473
+ }
474
+ property bool landingWait: false
475
+ // Where the landing ask's window starts, so its own reply is told from another ask's.
476
+ property int landingStart: -1
477
+ // The wait ends on the ask's outcome, rows covering the cursor or not, or its refusal; a wheel, drag, flick or bar press ends it for an ask never answered.
478
+ function landIfReady() {
479
+ if (!root.landingWait || (root.windowOwed() && root.pane.held !== root.landingStart)) return
480
+ root.landingWait = false
481
+ root.revealCursor()
482
+ }
483
+ // A refused or unanswered window leaves the view where it is and frees the drift asks; the operator owns the view from here.
484
+ function endLanding(reveal) {
485
+ if (!root.landingWait) return
486
+ root.landingWait = false
487
+ if (reveal) root.revealCursor()
488
+ else coalesce.restart()
489
+ }
490
+ // No window while hidden, while a filter narrows rows already held, nor while a listing is out, whose windows are the directory asked for.
491
+ function canAsk() { return root.visible && root.pane.total !== 0 && root.pane.shown === null && !root.pane.listInFlight }
492
+ function askWindow(ask) {
493
+ if (ask !== null && root.canAsk())
494
+ root.pane.backend.window(ask.start, ask.count)
495
+ }
496
+
497
+ function requestIfDrifted() {
498
+ // The view is parked on the old rows until the landing window arrives; a drift ask from there would fetch the window it left.
499
+ if (root.landingWait) return
500
+ var range = root.visibleRange()
501
+ root.askWindow(GridGeometry.driftAsk(root.windowPlan, range.first, range.last, root.pane.held, root.pane.rows.length, root.pane.total))
502
+ }
503
+
504
+ // Thumbs.viewport takes geometry and no thumb-specific state, so a tile row is handed to it the
505
+ // same way a text row is; the answer is then multiplied out into item indices.
506
+ function visibleRange() {
507
+ var view = Thumbs.viewport(root.viewTop(), root.cellHeightPx, root.visibleTileRows, root.tileRows)
508
+ return {
509
+ first: view.first * root.columns,
510
+ last: Math.min(root.pane.shownTotal - 1, (view.last + 1) * root.columns - 1)
511
+ }
512
+ }
513
+
514
+ // Returning parks the view on the shared cursor once the reset rows land.
515
+ property bool hiddenHeld: false
516
+ // Last parked contentY and loop turns spent; only a value stable across turns ends the hold.
517
+ property real restoreY: -1
518
+ property int restoreTicks: 0
519
+ onVisibleChanged: {
520
+ if (!root.visible) {
521
+ coalesce.stop()
522
+ settle.stop()
523
+ root.landingWait = false
524
+ root.hiddenHeld = true
525
+ root.restoreY = -1
526
+ root.restoreTicks = 0
527
+ return
528
+ }
529
+ if (root.hiddenHeld)
530
+ root.restoreCursorView()
531
+ }
532
+ // Count changes inside StableModel's layout, where a move refills every tile between the top and the cursor; resized follows it.
533
+ function modelResized() { root.landingWait = false; root.placeCursor(); root.prebuild.landed(); root.regrowCache() }
534
+ function placeCursor() {
535
+ root.currentIndex = root.cursorView
536
+ if (root.hiddenHeld && root.visible && root.count > 0)
537
+ root.restoreCursorView()
538
+ else root.revealCursor()
539
+ }
540
+ // A cursor reveal parks its tile in one pass, the last row's gap included, so no later turn moves a view already drawn.
541
+ function containTile(viewIndex) { root.positionViewAtIndex(viewIndex, GridView.Contain); root.keepLastRowClear(viewIndex) }
542
+ // Contain parks a last-row cursor flush on the view bottom, so keep the tiles one gap clear; a row already clear stays put.
543
+ function keepLastRowClear(view) {
544
+ if (root.contentHeight + root.topMargin + root.bottomMargin <= root.height || root.columns < 1 || view < 0) return
545
+ if (Math.floor(view / root.columns) !== root.tileRows - 1) return
546
+ root.contentY = Math.max(root.contentY, root.originY + root.contentHeight - Theme.chromeHeight + Theme.spacing.gap - root.height)
547
+ }
548
+ function restoreCursorView() {
549
+ // A queued turn arriving after the hold ended is stale.
550
+ if (!root.hiddenHeld || !root.visible)
551
+ return
552
+ if (!root.pane) {
553
+ root.hiddenHeld = false
554
+ return
555
+ }
556
+ // The model reset may still be landing; a later turn retries.
557
+ if (root.count === 0 && root.pane.shownTotal > 0) {
558
+ root.deferRestore()
559
+ return
560
+ }
561
+ // An empty listing and a filtered-away cursor have no view to park, so the hold ends here.
562
+ var view = Filter.viewOf(root.pane.shown, root.pane.cursorIndex)
563
+ if (root.count === 0 || view < 0) {
564
+ root.hiddenHeld = false
565
+ return
566
+ }
567
+ root.forceLayout()
568
+ root.positionViewAtIndex(view, GridView.Contain)
569
+ root.keepLastRowClear(view)
570
+ // Only a value stable across turns ends the hold; an optimistic position never releases it.
571
+ if (root.coversCursor(view) && root.contentY === root.restoreY) {
572
+ root.hiddenHeld = false
573
+ root.restoreY = -1
574
+ root.restoreTicks = 0
575
+ settle.restart()
576
+ return
577
+ }
578
+ root.restoreY = root.contentY
579
+ root.deferRestore()
580
+ }
581
+ // Restore gives up after this many turns, the bound the hidden return waits on.
582
+ readonly property int restoreMaxTurns: 60
583
+ // The parked check the return asserts through: the cursor tile overlaps the viewport.
584
+ function coversCursor(view) {
585
+ var row = Math.floor(view / Math.max(1, root.columns))
586
+ var top = row * root.cellHeightPx
587
+ return top < root.viewTop() + root.height && top + root.cellHeightPx > root.viewTop()
588
+ }
589
+ // The viewport's top in tile space: a column change re-flows the tiles and moves originY, so contentY alone reads the wrong row.
590
+ function viewTop() { return root.contentY - root.originY }
591
+ // One more loop turn, with a deadlock guard that ends the hold rather than keeping it.
592
+ function deferRestore() {
593
+ if (!root.visible)
594
+ return
595
+ if (root.restoreTicks >= root.restoreMaxTurns) {
596
+ root.hiddenHeld = false
597
+ root.restoreY = -1
598
+ root.restoreTicks = 0
599
+ settle.restart()
600
+ return
601
+ }
602
+ root.restoreTicks += 1
603
+ Qt.callLater(root.restoreCursorView)
604
+ }
605
+
606
+ Connections {
607
+ target: root.pane.backend
608
+ ignoreUnknownSignals: true
609
+ function onFailed(where, input, message, mode) { if (where === "window") root.endLanding(true) }
610
+ }
611
+
612
+ Connections {
613
+ target: root.pane
614
+ function onRowsChanged() { root.takeHeld(); root.landIfReady() }
615
+ function onRenamingIndexChanged() { root.renameRetirement = null; root.queueRenameLayout() }
616
+ function onRenameRequestChanged() { root.queueRenameLayout() }
617
+ function onFilterQueryChanged() {
618
+ if (!root.visible) return
619
+ var work = Filter.cut({ask: [], drop: []}, root.pane.shown, root.pane.thumbState)
620
+ work.drop = work.drop.filter(function(index) { return index !== root.pane.previewIndex })
621
+ if (work.drop.length > 0) {
622
+ root.pane.backend.thumbcancel(work.drop)
623
+ root.thumbsApplied(work)
624
+ }
625
+ // A scroll never cancels a size the user asked for (src/dirsize.js).
626
+ settle.restart()
627
+ }
628
+ }
629
+
630
+ Connections {
631
+ target: ViewState
632
+ function onThumbnailModeChanged() { if (root.visible) settle.restart() }
633
+ function onThumbnailPixelsChanged() { if (root.visible) settle.restart() }
634
+ }
635
+
636
+ function requestThumbs() {
637
+ if (!root.visible || root.pane.listInFlight || !root.pane.storageKnown)
638
+ return
639
+ var range = root.visibleRange()
640
+ var span = Filter.span(root.pane.shown, range.first, range.last)
641
+ var work = Filter.cut(Thumbs.plan(root.pane.thumbState, root.pane.rows, root.pane.held, span.first, span.last, ViewState.thumbnailMode), root.pane.shown, root.pane.thumbState)
642
+ work.drop = work.drop.filter(function (index) { return index !== root.pane.previewIndex })
643
+ root.pane.backend.thumbcancel(work.drop)
644
+ work.cacheOnly = ExtThumbs.cacheOnly(root.pane.storageClass, ViewState.preview)
645
+ root.pane.backend.thumb(work.ask, work.cacheOnly)
646
+ root.thumbsApplied(work)
647
+ }
648
+
649
+ function requestDirSizes() {
650
+ // Folder sizes are measured only when the user asks: a ⚖️ click, see Pane.measureDirs.
651
+ return
652
+ if (!root.visible || root.pane.shownTotal === 0 || root.pane.listInFlight)
653
+ return
654
+ // A tile draws no size, so the grid never asks, whatever rows are visible.
655
+ if (!DirSizes.wantsSizes("grid", ViewState.hiddenCols, root.pane.storageClass, root.pane.storageKnown))
656
+ return
657
+ var range = root.visibleRange()
658
+ var span = Filter.span(root.pane.shown, range.first, range.last)
659
+ var ask = Filter.keep(DirSizes.plan(root.pane.dirSizeState, root.pane.rows, root.pane.held, span.first, span.last), root.pane.shown)
660
+ if (ask.length > 0)
661
+ root.pane.backend.dirsize(ask)
662
+ root.dirSizesApplied(ask)
663
+ }
664
+ }