flea-qml 0.0.0-stage → 0.1.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 (625) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +478 -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 +402 -0
  51. package/src/archiveops.js +697 -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 +129 -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/transfer.js +669 -0
  82. package/src/trash-record.js +41 -0
  83. package/src/trash.js +210 -0
  84. package/src/trashbrowse.js +326 -0
  85. package/src/uistate.js +393 -0
  86. package/src/uistore.js +168 -0
  87. package/src/vendor/LICENSES/Apache-2.0.txt +202 -0
  88. package/src/vendor/LICENSES/MIT-katex-2015.txt +27 -0
  89. package/src/vendor/LICENSES/MIT-katex.txt +21 -0
  90. package/src/vendor/LICENSES/MIT-mermaid.txt +21 -0
  91. package/src/vendor/LICENSES/MIT-pele.txt +40 -0
  92. package/src/vendor/LICENSES/MIT-perseus.txt +18 -0
  93. package/src/vendor/LICENSES/MIT-temml.txt +21 -0
  94. package/src/vendor/pele.js +145 -0
  95. package/src/vendor/temml.mjs +14708 -0
  96. package/src/watch.js +98 -0
  97. package/src/wayland/client.js +109 -0
  98. package/src/wayland/protocol.js +55 -0
  99. package/src/wayland/protocols/ext-data-control-v1.xml +276 -0
  100. package/src/wayland/protocols/wayland.xml +3248 -0
  101. package/src/wayland/protocols/wlr-data-control-unstable-v1.xml +278 -0
  102. package/src/wayland/resource-io.js +6 -0
  103. package/src/wayland/socket-discovery.js +26 -0
  104. package/src/wayland/transport-posix.js +120 -0
  105. package/src/wayland/transport-win32.js +11 -0
  106. package/src/wayland/transport.js +3 -0
  107. package/src/wayland/win32-resources.js +80 -0
  108. package/src/wayland/win32-wire.js +62 -0
  109. package/test/archive.test.js +80 -0
  110. package/test/bench-markdown-scroll.mjs +190 -0
  111. package/test/clip-host.test.js +113 -0
  112. package/test/code-preview.test.js +35 -0
  113. package/test/compare-ui-paths.test.js +24 -0
  114. package/test/compare.test.js +54 -0
  115. package/test/delete-trash.test.js +67 -0
  116. package/test/dirsize.test.js +138 -0
  117. package/test/file-ops.test.js +241 -0
  118. package/test/find-contents.test.js +161 -0
  119. package/test/find-input.test.js +66 -0
  120. package/test/fixtures/pele-parity.json +1006 -0
  121. package/test/highlight-launcher.test.js +35 -0
  122. package/test/html-preview.test.js +22 -0
  123. package/test/input.test.js +15 -0
  124. package/test/keymap.test.js +26 -0
  125. package/test/language-icons.test.js +36 -0
  126. package/test/launcher.test.js +51 -0
  127. package/test/manual-code-scroll.mjs +28 -0
  128. package/test/manual-column-scroll.mjs +24 -0
  129. package/test/manual-compare-ui.mjs +20 -0
  130. package/test/manual-find-status.mjs +37 -0
  131. package/test/manual-html-security.mjs +23 -0
  132. package/test/manual-html-ui.mjs +30 -0
  133. package/test/manual-syntax-preview.mjs +26 -0
  134. package/test/manual-trash-ui.mjs +86 -0
  135. package/test/markdown-diagrams.test.js +93 -0
  136. package/test/markdown-html.test.js +105 -0
  137. package/test/mathml.test.js +92 -0
  138. package/test/menu-transfer.test.js +57 -0
  139. package/test/office-preview.test.js +154 -0
  140. package/test/pele-parity.test.js +28 -0
  141. package/test/places.test.js +134 -0
  142. package/test/preview-keys.test.js +60 -0
  143. package/test/preview-language.test.js +22 -0
  144. package/test/status-filename.test.js +20 -0
  145. package/test/transfer-replace-merge.test.js +187 -0
  146. package/test/trash-address.test.js +23 -0
  147. package/test/trash-view.test.js +37 -0
  148. package/test/trashbrowse.test.js +135 -0
  149. package/ui/AboutFacts.qml +78 -0
  150. package/ui/ArchiveCards.qml +68 -0
  151. package/ui/ArchiveCompressDialog.qml +378 -0
  152. package/ui/ArchivePasswordDialog.qml +257 -0
  153. package/ui/Backend.qml +771 -0
  154. package/ui/BulkOldNames.qml +47 -0
  155. package/ui/BulkRenameDialog.qml +380 -0
  156. package/ui/CardFrame.qml +67 -0
  157. package/ui/CardScroll.qml +79 -0
  158. package/ui/CheckBox.qml +73 -0
  159. package/ui/ChromeBar.qml +360 -0
  160. package/ui/ChromeButton.qml +131 -0
  161. package/ui/ChromeModes.qml +43 -0
  162. package/ui/CodeLines.qml +256 -0
  163. package/ui/CodeRefusal.qml +52 -0
  164. package/ui/CollideConfirm.qml +147 -0
  165. package/ui/CollideHost.qml +167 -0
  166. package/ui/ColumnPane.qml +523 -0
  167. package/ui/ColumnRow.qml +380 -0
  168. package/ui/ColumnsArea.qml +594 -0
  169. package/ui/ColumnsLanding.qml +147 -0
  170. package/ui/CompareView.qml +321 -0
  171. package/ui/ContextMenu.qml +743 -0
  172. package/ui/ConvertDialog.qml +456 -0
  173. package/ui/CountedWorker.qml +7 -0
  174. package/ui/Crumb.qml +64 -0
  175. package/ui/CrumbDrop.qml +25 -0
  176. package/ui/CsvTable.qml +394 -0
  177. package/ui/CursorMark.qml +41 -0
  178. package/ui/DefaultClaim.qml +130 -0
  179. package/ui/DeviceLock.qml +47 -0
  180. package/ui/DeviceMounts.qml +540 -0
  181. package/ui/DialogButton.qml +150 -0
  182. package/ui/DialogField.qml +147 -0
  183. package/ui/DialogHeader.qml +31 -0
  184. package/ui/DialogScrim.qml +20 -0
  185. package/ui/DialogTitle.qml +37 -0
  186. package/ui/Divider.qml +9 -0
  187. package/ui/DropInto.qml +126 -0
  188. package/ui/DropTarget.qml +35 -0
  189. package/ui/DropboxMark.qml +60 -0
  190. package/ui/EmptyState.qml +150 -0
  191. package/ui/EscapeHint.qml +11 -0
  192. package/ui/FactsTable.qml +54 -0
  193. package/ui/FastScrollHandler.qml +476 -0
  194. package/ui/FatNamesConfirm.qml +157 -0
  195. package/ui/Favourites.qml +143 -0
  196. package/ui/FigureService.qml +120 -0
  197. package/ui/FileDrag.qml +267 -0
  198. package/ui/FilterStrip.qml +133 -0
  199. package/ui/FitMetrics.qml +22 -0
  200. package/ui/FlashDriveRows.qml +137 -0
  201. package/ui/FlashHost.qml +72 -0
  202. package/ui/FlashImageRow.qml +104 -0
  203. package/ui/FlashRunner.qml +119 -0
  204. package/ui/FlashStepRow.qml +172 -0
  205. package/ui/FlashStrip.qml +38 -0
  206. package/ui/FlashView.qml +397 -0
  207. package/ui/FleaMark.qml +88 -0
  208. package/ui/FlyoutFade.qml +23 -0
  209. package/ui/FontPane.qml +170 -0
  210. package/ui/Glass.qml +114 -0
  211. package/ui/GlassTagger.qml +59 -0
  212. package/ui/Glyph.qml +64 -0
  213. package/ui/GlyphSolid.qml +22 -0
  214. package/ui/GridArea.qml +664 -0
  215. package/ui/GridTile.qml +325 -0
  216. package/ui/GvfsBridge.qml +164 -0
  217. package/ui/Header.qml +433 -0
  218. package/ui/HoverTimers.qml +39 -0
  219. package/ui/HtmlClip.qml +30 -0
  220. package/ui/HtmlPane.qml +63 -0
  221. package/ui/HyprlandMark.qml +45 -0
  222. package/ui/Ipc.qml +1005 -0
  223. package/ui/IpcControls.qml +7 -0
  224. package/ui/IpcMenuState.qml +48 -0
  225. package/ui/IpcPreviewState.qml +185 -0
  226. package/ui/JumpPath.qml +51 -0
  227. package/ui/KeymapSheet.qml +561 -0
  228. package/ui/KeymapSheetResult.qml +89 -0
  229. package/ui/KindStack.qml +40 -0
  230. package/ui/LangMark.qml +51 -0
  231. package/ui/LangMarkLoader.qml +26 -0
  232. package/ui/List.qml +480 -0
  233. package/ui/LoadingState.qml +54 -0
  234. package/ui/LocalSend.qml +56 -0
  235. package/ui/LocalSendMark.qml +73 -0
  236. package/ui/MarkdownBlockView.qml +311 -0
  237. package/ui/MarkdownBlocks.qml +35 -0
  238. package/ui/MarkdownFigure.qml +254 -0
  239. package/ui/MarkdownImages.qml +72 -0
  240. package/ui/MarkdownList.qml +81 -0
  241. package/ui/MarkdownMathsText.qml +97 -0
  242. package/ui/MarkdownPane.qml +83 -0
  243. package/ui/MarkdownPictures.qml +41 -0
  244. package/ui/MarkdownQuote.qml +52 -0
  245. package/ui/MarkdownRemote.qml +82 -0
  246. package/ui/MarkdownSource.qml +155 -0
  247. package/ui/MarkdownTable.qml +222 -0
  248. package/ui/MarkdownTableScroll.qml +64 -0
  249. package/ui/MarkdownTableWheel.qml +126 -0
  250. package/ui/MarkdownText.qml +87 -0
  251. package/ui/MarkdownWorker.js +132 -0
  252. package/ui/MatchText.qml +99 -0
  253. package/ui/MediaSession.qml +38 -0
  254. package/ui/MediaSound.qml +26 -0
  255. package/ui/MediaStrip.qml +191 -0
  256. package/ui/MediaTrack.qml +36 -0
  257. package/ui/MediaVolume.qml +54 -0
  258. package/ui/MenuActionDialog.qml +396 -0
  259. package/ui/MenuEdgeFade.qml +24 -0
  260. package/ui/MenuHost.qml +227 -0
  261. package/ui/MenuRow.qml +351 -0
  262. package/ui/MountListing.qml +100 -0
  263. package/ui/NetworkDialog.qml +435 -0
  264. package/ui/NetworkForm.qml +426 -0
  265. package/ui/NetworkMounts.qml +913 -0
  266. package/ui/NetworkPlaces.qml +127 -0
  267. package/ui/OpenWithDialog.qml +613 -0
  268. package/ui/Opener.qml +115 -0
  269. package/ui/Pane.qml +1296 -0
  270. package/ui/PaneMenuActions.qml +527 -0
  271. package/ui/PanePath.qml +90 -0
  272. package/ui/PaneRail.qml +239 -0
  273. package/ui/PaneStates.qml +88 -0
  274. package/ui/PaneSwap.qml +339 -0
  275. package/ui/PaneWire.qml +605 -0
  276. package/ui/ParkedWait.qml +9 -0
  277. package/ui/PathEntry.qml +186 -0
  278. package/ui/PathJump.qml +400 -0
  279. package/ui/PdfViewer.qml +297 -0
  280. package/ui/PermissionsDialog.qml +658 -0
  281. package/ui/PermissionsHeadings.qml +31 -0
  282. package/ui/PhoneMounts.qml +67 -0
  283. package/ui/PickerAnswers.qml +75 -0
  284. package/ui/PickerBox.qml +26 -0
  285. package/ui/PickerChrome.qml +295 -0
  286. package/ui/PickerFilter.qml +97 -0
  287. package/ui/PickerGrid.qml +308 -0
  288. package/ui/PickerHeader.qml +28 -0
  289. package/ui/PickerLifecycle.qml +27 -0
  290. package/ui/PickerList.qml +218 -0
  291. package/ui/PickerListing.qml +149 -0
  292. package/ui/PickerPathBar.qml +127 -0
  293. package/ui/PickerPlaces.qml +189 -0
  294. package/ui/PickerRecent.qml +92 -0
  295. package/ui/PickerSave.qml +101 -0
  296. package/ui/PickerSelection.qml +155 -0
  297. package/ui/PickerWindow.qml +846 -0
  298. package/ui/PowerSectorsReader.qml +10 -0
  299. package/ui/PrebuildDriver.qml +146 -0
  300. package/ui/Preview.qml +1004 -0
  301. package/ui/PreviewAnimation.qml +24 -0
  302. package/ui/PreviewArchive.qml +66 -0
  303. package/ui/PreviewColumn.qml +551 -0
  304. package/ui/PreviewEdge.qml +63 -0
  305. package/ui/PreviewFacts.qml +30 -0
  306. package/ui/PreviewFactsLine.qml +34 -0
  307. package/ui/PreviewHtml.qml +233 -0
  308. package/ui/PreviewImage.qml +253 -0
  309. package/ui/PreviewImagePan.qml +13 -0
  310. package/ui/PreviewImageSharp.qml +32 -0
  311. package/ui/PreviewLines.qml +106 -0
  312. package/ui/PreviewMarkdown.qml +706 -0
  313. package/ui/PreviewMedia.qml +250 -0
  314. package/ui/PreviewPdf.qml +482 -0
  315. package/ui/PreviewScroll.qml +201 -0
  316. package/ui/PreviewSwap.qml +335 -0
  317. package/ui/PreviewText.qml +149 -0
  318. package/ui/ProtocolChip.qml +18 -0
  319. package/ui/QuickLookArchive.qml +38 -0
  320. package/ui/QuickLookBar.qml +103 -0
  321. package/ui/QuickLookPrepare.qml +355 -0
  322. package/ui/QuickLookSwap.qml +10 -0
  323. package/ui/QuickLookWarm.qml +65 -0
  324. package/ui/RailDrop.qml +155 -0
  325. package/ui/RailHeading.qml +19 -0
  326. package/ui/RailPlaces.qml +38 -0
  327. package/ui/RailTrashRow.qml +67 -0
  328. package/ui/RenameField.qml +353 -0
  329. package/ui/RendererRetry.qml +11 -0
  330. package/ui/ResizeHandle.qml +52 -0
  331. package/ui/Reveal.qml +54 -0
  332. package/ui/Row.qml +476 -0
  333. package/ui/RowDrag.qml +213 -0
  334. package/ui/RowDropTarget.qml +27 -0
  335. package/ui/RunCard.qml +286 -0
  336. package/ui/Scripts.qml +65 -0
  337. package/ui/SearchStrip.qml +232 -0
  338. package/ui/SelectionBand.qml +140 -0
  339. package/ui/SelectionPreview.qml +370 -0
  340. package/ui/SettingsFavourite.qml +122 -0
  341. package/ui/SettingsGroup.qml +96 -0
  342. package/ui/SettingsHint.qml +12 -0
  343. package/ui/SettingsMetrics.qml +29 -0
  344. package/ui/SettingsPane.qml +178 -0
  345. package/ui/SettingsPanel.qml +547 -0
  346. package/ui/SettingsRail.qml +128 -0
  347. package/ui/SettingsRow.qml +409 -0
  348. package/ui/SettingsRuler.qml +85 -0
  349. package/ui/SettingsSegment.qml +85 -0
  350. package/ui/ShareBrowser.qml +113 -0
  351. package/ui/ShareLink.qml +67 -0
  352. package/ui/ShelfPins.qml +101 -0
  353. package/ui/Sidebar.qml +732 -0
  354. package/ui/SidebarRow.qml +358 -0
  355. package/ui/Spinner.qml +60 -0
  356. package/ui/StableModel.qml +89 -0
  357. package/ui/StateMessage.qml +84 -0
  358. package/ui/StatusBar.qml +512 -0
  359. package/ui/StatusFileName.qml +27 -0
  360. package/ui/TabBar.qml +673 -0
  361. package/ui/TabDragGeometry.qml +60 -0
  362. package/ui/TagMenuMark.qml +52 -0
  363. package/ui/TagRailSection.qml +53 -0
  364. package/ui/TagSlot.qml +40 -0
  365. package/ui/TagState.qml +150 -0
  366. package/ui/TagSwatch.qml +28 -0
  367. package/ui/Taildrop.qml +86 -0
  368. package/ui/TailscaleMark.qml +50 -0
  369. package/ui/Theme.qml +460 -0
  370. package/ui/ThemeColors.qml +43 -0
  371. package/ui/TransferCard.qml +239 -0
  372. package/ui/TrashConfirm.qml +129 -0
  373. package/ui/TrashDropHandler.qml +11 -0
  374. package/ui/TrashHost.qml +202 -0
  375. package/ui/TrashMonitor.qml +30 -0
  376. package/ui/TrashToolbar.qml +19 -0
  377. package/ui/TrashView.qml +492 -0
  378. package/ui/UnlockDialog.qml +450 -0
  379. package/ui/UnlockHost.qml +206 -0
  380. package/ui/UpdateCheck.qml +97 -0
  381. package/ui/UserDirs.qml +25 -0
  382. package/ui/ViewState.qml +565 -0
  383. package/ui/ViewportScrollBar.qml +195 -0
  384. package/ui/ViewportScrollBars.qml +25 -0
  385. package/ui/WebPreview.qml +33 -0
  386. package/ui/WebPreviewView.qml +26 -0
  387. package/ui/WindowBody.qml +827 -0
  388. package/ui/WindowDrag.qml +35 -0
  389. package/ui/boot/Commons/AudioNodes.qml +50 -0
  390. package/ui/boot/Commons/AudioNodesModel.js +96 -0
  391. package/ui/boot/Commons/Border.qml +243 -0
  392. package/ui/boot/Commons/BorderGeometry.js +373 -0
  393. package/ui/boot/Commons/Color.qml +258 -0
  394. package/ui/boot/Commons/I18n.qml +118 -0
  395. package/ui/boot/Commons/InputDevices.qml +112 -0
  396. package/ui/boot/Commons/InputMethodState.qml +38 -0
  397. package/ui/boot/Commons/IpcRegistry.qml +77 -0
  398. package/ui/boot/Commons/Numbers.js +19 -0
  399. package/ui/boot/Commons/Plural.js +91 -0
  400. package/ui/boot/Commons/ShellIpc.qml +12 -0
  401. package/ui/boot/Commons/Style.qml +561 -0
  402. package/ui/boot/Commons/Translations.qml +100 -0
  403. package/ui/boot/Commons/UntypedInput.qml +152 -0
  404. package/ui/boot/Commons/Util.qml +188 -0
  405. package/ui/boot/Commons/qmldir +13 -0
  406. package/ui/boot/LICENSE-omarchy +20 -0
  407. package/ui/boot/Ui/BackgroundMedia.qml +49 -0
  408. package/ui/boot/Ui/BarIconButton.qml +106 -0
  409. package/ui/boot/Ui/BarIconContent.qml +38 -0
  410. package/ui/boot/Ui/BarIndicator.qml +53 -0
  411. package/ui/boot/Ui/BarWidget.qml +50 -0
  412. package/ui/boot/Ui/BorderOverlay.qml +54 -0
  413. package/ui/boot/Ui/BorderSurface.qml +40 -0
  414. package/ui/boot/Ui/Button.qml +224 -0
  415. package/ui/boot/Ui/ButtonGroup.qml +131 -0
  416. package/ui/boot/Ui/ConfirmDialog.qml +134 -0
  417. package/ui/boot/Ui/CursorSurface.qml +42 -0
  418. package/ui/boot/Ui/Dropdown.qml +245 -0
  419. package/ui/boot/Ui/FilterInput.qml +26 -0
  420. package/ui/boot/Ui/IconContentBounds.qml +141 -0
  421. package/ui/boot/Ui/KeyboardPanel.qml +453 -0
  422. package/ui/boot/Ui/MultiSelect.qml +624 -0
  423. package/ui/boot/Ui/NumberField.qml +86 -0
  424. package/ui/boot/Ui/OpticalGlyph.qml +68 -0
  425. package/ui/boot/Ui/OverlayWindow.qml +102 -0
  426. package/ui/boot/Ui/Panel.qml +60 -0
  427. package/ui/boot/Ui/PanelActionButton.qml +105 -0
  428. package/ui/boot/Ui/PanelController.qml +16 -0
  429. package/ui/boot/Ui/PanelHero.qml +112 -0
  430. package/ui/boot/Ui/PanelKeyCatcher.qml +100 -0
  431. package/ui/boot/Ui/PanelSectionHeader.qml +31 -0
  432. package/ui/boot/Ui/PanelSeparator.qml +19 -0
  433. package/ui/boot/Ui/PanelSlider.qml +156 -0
  434. package/ui/boot/Ui/PanelToolTip.qml +50 -0
  435. package/ui/boot/Ui/PluginBarApi.qml +89 -0
  436. package/ui/boot/Ui/PointerMoveGate.qml +54 -0
  437. package/ui/boot/Ui/PopupCard.qml +181 -0
  438. package/ui/boot/Ui/ScreenMoveRemap.qml +43 -0
  439. package/ui/boot/Ui/SearchableDropdown.qml +354 -0
  440. package/ui/boot/Ui/SizedImage.qml +125 -0
  441. package/ui/boot/Ui/SpeedTestOverlay.qml +412 -0
  442. package/ui/boot/Ui/TextField.qml +58 -0
  443. package/ui/boot/Ui/Toggle.qml +118 -0
  444. package/ui/boot/Ui/ToggleSwitch.qml +115 -0
  445. package/ui/boot/Ui/WidgetButton.qml +172 -0
  446. package/ui/boot/Ui/qmldir +41 -0
  447. package/ui/boot/fleatab.qml +50 -0
  448. package/ui/boot/picker.qml +39 -0
  449. package/ui/boot/shell.qml +122 -0
  450. package/ui/boot/tabtearoff.qml +51 -0
  451. package/ui/js/Anchor.js +379 -0
  452. package/ui/js/AnchorHold.js +162 -0
  453. package/ui/js/Archive.js +157 -0
  454. package/ui/js/ArchiveCard.js +44 -0
  455. package/ui/js/ArchiveOps.js +44 -0
  456. package/ui/js/BackReturn.js +118 -0
  457. package/ui/js/BulkRename.js +100 -0
  458. package/ui/js/Buttons.js +54 -0
  459. package/ui/js/ChromeKeys.js +116 -0
  460. package/ui/js/ClipMarks.js +73 -0
  461. package/ui/js/ClipSelection.js +67 -0
  462. package/ui/js/Clipboard.js +179 -0
  463. package/ui/js/Cloud.js +97 -0
  464. package/ui/js/CodeRuns.js +72 -0
  465. package/ui/js/Collide.js +212 -0
  466. package/ui/js/ColumnFit.js +28 -0
  467. package/ui/js/ColumnMenu.js +111 -0
  468. package/ui/js/Columns.js +298 -0
  469. package/ui/js/ColumnsCarry.js +103 -0
  470. package/ui/js/Compare.js +74 -0
  471. package/ui/js/Contrast.js +157 -0
  472. package/ui/js/ControlReader.js +42 -0
  473. package/ui/js/Convert.js +52 -0
  474. package/ui/js/CopyAs.js +52 -0
  475. package/ui/js/Crumbs.js +178 -0
  476. package/ui/js/Csv.js +231 -0
  477. package/ui/js/Density.js +44 -0
  478. package/ui/js/Devices.js +440 -0
  479. package/ui/js/DirSizes.js +180 -0
  480. package/ui/js/Drag.js +364 -0
  481. package/ui/js/DragOut.js +166 -0
  482. package/ui/js/DropDev.js +52 -0
  483. package/ui/js/Dropbox.js +41 -0
  484. package/ui/js/Eject.js +217 -0
  485. package/ui/js/Errors.js +188 -0
  486. package/ui/js/ExtThumbs.js +115 -0
  487. package/ui/js/Facts.js +402 -0
  488. package/ui/js/FigureDate.js +14 -0
  489. package/ui/js/Filter.js +285 -0
  490. package/ui/js/Find.js +46 -0
  491. package/ui/js/Flash.js +184 -0
  492. package/ui/js/FlashCard.js +79 -0
  493. package/ui/js/FlashEndings.js +125 -0
  494. package/ui/js/FlashPane.js +116 -0
  495. package/ui/js/FleaBin.js +12 -0
  496. package/ui/js/Focus.js +502 -0
  497. package/ui/js/FolderSorts.js +108 -0
  498. package/ui/js/FolderViews.js +44 -0
  499. package/ui/js/Format.js +305 -0
  500. package/ui/js/Fuzzy.js +141 -0
  501. package/ui/js/GlassTag.js +72 -0
  502. package/ui/js/Grid.js +33 -0
  503. package/ui/js/GridGeometry.js +90 -0
  504. package/ui/js/GridNames.js +153 -0
  505. package/ui/js/GvfsBridge.js +200 -0
  506. package/ui/js/HostClipboard.js +29 -0
  507. package/ui/js/Icons.js +218 -0
  508. package/ui/js/Input.js +50 -0
  509. package/ui/js/Jump.js +200 -0
  510. package/ui/js/KeyName.js +64 -0
  511. package/ui/js/Keymap.js +401 -0
  512. package/ui/js/Kinds.js +164 -0
  513. package/ui/js/LICENSES/ISC-lucide.txt +43 -0
  514. package/ui/js/LangMarkPaths.js +47 -0
  515. package/ui/js/LangMarks.js +120 -0
  516. package/ui/js/Lists.js +11 -0
  517. package/ui/js/LocalSend.js +39 -0
  518. package/ui/js/LockedMenu.js +63 -0
  519. package/ui/js/MakeDefault.js +186 -0
  520. package/ui/js/MarkBox.js +7 -0
  521. package/ui/js/Markdown.js +119 -0
  522. package/ui/js/MarkdownLists.js +86 -0
  523. package/ui/js/MarkdownMaths.js +58 -0
  524. package/ui/js/MarkdownPictures.js +32 -0
  525. package/ui/js/MarkdownPrepared.js +139 -0
  526. package/ui/js/MarkdownTableFit.js +34 -0
  527. package/ui/js/Marks.js +148 -0
  528. package/ui/js/Marquee.js +96 -0
  529. package/ui/js/Match.js +93 -0
  530. package/ui/js/Material.js +109 -0
  531. package/ui/js/MdBlocks.js +437 -0
  532. package/ui/js/MdBreak.js +71 -0
  533. package/ui/js/MdChunks.js +70 -0
  534. package/ui/js/MdContainer.js +137 -0
  535. package/ui/js/MdDocument.js +337 -0
  536. package/ui/js/MdEmph.js +97 -0
  537. package/ui/js/MdEntity.js +108 -0
  538. package/ui/js/MdEntityTable.js +223 -0
  539. package/ui/js/MdEscape.js +59 -0
  540. package/ui/js/MdFront.js +37 -0
  541. package/ui/js/MdHold.js +32 -0
  542. package/ui/js/MdHtml.js +307 -0
  543. package/ui/js/MdHtmlBlock.js +290 -0
  544. package/ui/js/MdHtmlHeading.js +53 -0
  545. package/ui/js/MdHtmlImage.js +179 -0
  546. package/ui/js/MdInline.js +154 -0
  547. package/ui/js/MdItems.js +212 -0
  548. package/ui/js/MdLeaf.js +309 -0
  549. package/ui/js/MdLink.js +196 -0
  550. package/ui/js/MdMath.js +67 -0
  551. package/ui/js/MdParagraphs.js +138 -0
  552. package/ui/js/MdRefs.js +232 -0
  553. package/ui/js/MdResolve.js +226 -0
  554. package/ui/js/MdRun.js +300 -0
  555. package/ui/js/MdUrl.js +226 -0
  556. package/ui/js/Menu.js +514 -0
  557. package/ui/js/MenuContext.js +85 -0
  558. package/ui/js/MenuFit.js +13 -0
  559. package/ui/js/MenuRefresh.js +74 -0
  560. package/ui/js/MenuWheel.js +35 -0
  561. package/ui/js/Messages.js +186 -0
  562. package/ui/js/Motion.js +16 -0
  563. package/ui/js/Mounts.js +320 -0
  564. package/ui/js/MouseNav.js +13 -0
  565. package/ui/js/Nav.js +329 -0
  566. package/ui/js/NetFs.js +26 -0
  567. package/ui/js/OpenWith.js +83 -0
  568. package/ui/js/Ops.js +585 -0
  569. package/ui/js/Palette.js +33 -0
  570. package/ui/js/PathBar.js +260 -0
  571. package/ui/js/Permissions.js +179 -0
  572. package/ui/js/Phones.js +112 -0
  573. package/ui/js/Picker.js +353 -0
  574. package/ui/js/PlaceMenu.js +96 -0
  575. package/ui/js/Places.js +265 -0
  576. package/ui/js/PreviewAsk.js +21 -0
  577. package/ui/js/PreviewKeys.js +155 -0
  578. package/ui/js/PreviewSettle.js +29 -0
  579. package/ui/js/PreviewSwap.js +101 -0
  580. package/ui/js/PropertyFacts.js +144 -0
  581. package/ui/js/Protocols.js +296 -0
  582. package/ui/js/QuickLookKinds.js +27 -0
  583. package/ui/js/QuickLookRect.js +24 -0
  584. package/ui/js/RailDrop.js +51 -0
  585. package/ui/js/RailKeys.js +87 -0
  586. package/ui/js/RailMenu.js +133 -0
  587. package/ui/js/Recent.js +135 -0
  588. package/ui/js/RecentMode.js +156 -0
  589. package/ui/js/Reload.js +60 -0
  590. package/ui/js/Renderer.js +9 -0
  591. package/ui/js/RunFile.js +143 -0
  592. package/ui/js/Scripts.js +28 -0
  593. package/ui/js/Scroll.js +304 -0
  594. package/ui/js/ScrollOff.js +69 -0
  595. package/ui/js/Search.js +478 -0
  596. package/ui/js/Selection.js +97 -0
  597. package/ui/js/Settings.js +476 -0
  598. package/ui/js/SettingsAbout.js +97 -0
  599. package/ui/js/SettingsShelf.js +52 -0
  600. package/ui/js/SheetKeys.js +42 -0
  601. package/ui/js/SheetQuery.js +281 -0
  602. package/ui/js/ShelfPile.js +27 -0
  603. package/ui/js/SlowClick.js +53 -0
  604. package/ui/js/SlowOp.js +6 -0
  605. package/ui/js/Sort.js +134 -0
  606. package/ui/js/Startup.js +63 -0
  607. package/ui/js/StateWords.js +17 -0
  608. package/ui/js/Status.js +238 -0
  609. package/ui/js/Swap.js +166 -0
  610. package/ui/js/TabMove.js +39 -0
  611. package/ui/js/Tabs.js +736 -0
  612. package/ui/js/Tags.js +134 -0
  613. package/ui/js/Taildrop.js +128 -0
  614. package/ui/js/Tap.js +174 -0
  615. package/ui/js/TextSize.js +107 -0
  616. package/ui/js/Thumbs.js +158 -0
  617. package/ui/js/Transfer.js +172 -0
  618. package/ui/js/Trash.js +81 -0
  619. package/ui/js/TrashDates.js +47 -0
  620. package/ui/js/TrashDrop.js +64 -0
  621. package/ui/js/UiState.js +438 -0
  622. package/ui/js/Unlock.js +152 -0
  623. package/ui/js/Update.js +130 -0
  624. package/ui/js/UserDirs.js +56 -0
  625. package/ui/qmldir +228 -0
@@ -0,0 +1,523 @@
1
+ import QtQuick
2
+ import qs.Commons
3
+ import qs.Ui
4
+ import "." as Flea
5
+ import "js/ClipMarks.js" as ClipMarks
6
+ import "js/Filter.js" as Filter
7
+ import "js/ExtThumbs.js" as ExtThumbs
8
+ import "js/Scroll.js" as Scroll
9
+ import "js/ScrollOff.js" as ScrollOff
10
+ import "js/Tap.js" as Tap
11
+ import "js/Thumbs.js" as Thumbs
12
+ import "js/DirSizes.js" as DirSizes
13
+ import "js/Sort.js" as Sort
14
+ import "js/DragOut.js" as DragOut
15
+ import "js/DropDev.js" as DropDev
16
+
17
+ // One Miller column: a scrolling list of ColumnRows over either a peeked directory or the pane's
18
+ // own listing window. It owns no state; the area above it decides which row is which.
19
+ Item {
20
+ id: root
21
+
22
+ // [{n, d, i}], from a peek or from the pane's own held window.
23
+ property var rows: []
24
+ property bool loadingRows: false
25
+ signal loadingShown(bool shown)
26
+ // The row this column's cursor is on, as an absolute index; -1 when this column has no cursor.
27
+ property int selectedIndex: -1
28
+ // The one row drawn as this column's cursor; a cursor move touches two delegates, not every live one.
29
+ Flea.CursorMark { id: cursorMark; row: root.selectedIndex }
30
+ // The row named here is the one the trail passes through: lifted like a hover, never accented.
31
+ property string liftedName: ""
32
+ // The pane whose listing this column draws, or null for a peek. Only that one column has a
33
+ // selection to paint, and pane.isSelected reads selectionVersion, so the delegate follows it.
34
+ property var pane: null
35
+ // The window pane plus this peek column's directory, device and writability, for a drag from its rows; null on the pane's own column.
36
+ property var peekSource: null
37
+ // A column that is not the active one reads back.
38
+ property bool dim: false
39
+ // The mode of a denied peek, or -1 when this column's directory was read and its rows are true.
40
+ property int lockedMode: -1
41
+ // Whether zero rows here means empty: false while a peek is still out, because a pending peek answers zero rows too, and false for the pane's own listing, whose empty answer is the hero ui/shell.qml lays over the area.
42
+ property bool drawsEmpty: false
43
+ // True when this column draws its size cell, the same flag its rows read as showSize.
44
+ readonly property bool showsSize: root.pane !== null && root.pane !== undefined
45
+ // Parked rows the active column built ahead of the next landing; only the pane's own column has a pane, so only it prebuilds.
46
+ readonly property Flea.PrebuildDriver prebuild: Flea.PrebuildDriver {
47
+ view: root.viewport
48
+ model: stable
49
+ pane: root.pane
50
+ limit: stable.warmRows
51
+ park: function (cell) { cell.live = false; cell.visible = false }
52
+ adopt: function (cell) { cell.live = true; cell.visible = true; cursorMark.place(cell) }
53
+ }
54
+ // One character budget for a row without the chevron, so a column lays its names out once.
55
+ readonly property int nameBudgetPlain: Theme.bodyAdvance > 0 ? Math.max(0, Math.floor((Scroll.contentWidth(root.width, Theme.spacing.rowPaddingX) - Theme.spacing.rowPaddingX - Theme.iconSize - Theme.spacing.gap - Theme.spacing.rowPaddingX - (root.showsSize ? Theme.column.size + 2 * Theme.spacing.gap : 0)) / Theme.bodyAdvance)) : -1
56
+ // The same terms plus the chevron slot, for the chosen directory alone.
57
+ readonly property int nameBudgetChevron: Theme.bodyAdvance > 0 ? Math.max(0, Math.floor((Scroll.contentWidth(root.width, Theme.spacing.rowPaddingX) - Theme.spacing.rowPaddingX - Theme.iconSize - Theme.spacing.gap - Theme.spacing.rowPaddingX - Theme.font.caption - (root.showsSize ? Theme.column.size + 2 * Theme.spacing.gap : 0)) / Theme.bodyAdvance)) : -1
58
+ // True for every shown pane but the rightmost one; the line sits on the pane edge and changes no width.
59
+ property bool showDivider: false
60
+ // Empty short-circuits before the library, the same rule ui/List.qml carries.
61
+ property bool clipEmpty: ClipMarks.isEmpty(root.pane ? root.pane.clipboard : null)
62
+ // The short-circuit above is the only release while empty, so a cut of a large directory frees its lookup here.
63
+ onClipEmptyChanged: { if (root.clipEmpty) ClipMarks.release() }
64
+
65
+ // isDir says which of the two things a neighbour column's row is: a directory the pane opens as
66
+ // its own listing, or a file it hands to the opener. See keys.toml's [[pointer]] table.
67
+ signal activated(string name, bool isDir)
68
+ signal picked(int index, int tapCount, int modifiers, bool onName)
69
+ // A row press, so the columns view can stop the slow-click timer before a
70
+ // hold past the interval fires while the button is still down.
71
+ signal rowPressed(int index)
72
+ // The row under a right click. Only the column carrying the pane's own listing answers it, because a peeked column's rows are another directory's and every menu action addresses the pane's cursor.
73
+ signal menuRequested(int index, var eventPoint)
74
+ // A right click that landed on no row, which only the pane's own column can answer for the same
75
+ // reason: the background menu acts on the directory being shown and a peek is not that directory.
76
+ signal backgroundMenuRequested(var eventPoint)
77
+ // A right click on a peek's row: the peek's directory becomes the listing with this row as the cursor, and the menu opens there.
78
+ signal neighbourMenuRequested(string name)
79
+ // A right click on a peek's empty space: the peek's drawn directory becomes the listing, and the background menu opens there once its rows land.
80
+ signal neighbourBackgroundRequested(var eventPoint)
81
+ // A middle click on a directory row, in any of the three columns: ui/js/Tap.js tappedTab opens it in
82
+ // a new tab, and ui/ColumnsArea.qml supplies which directory this column is showing.
83
+ signal tabRequested(var row)
84
+ // The thumbnail plan for this column's viewport, computed here and written by the pane, the grid's own contract.
85
+ signal thumbsApplied(var work)
86
+ signal dirSizesApplied(var ask)
87
+
88
+ // The listArea contract ui/ColumnsArea.qml drives the middle column through; the view is private.
89
+ function positionViewAtIndex(index, mode) { view.positionViewAtIndex(index, mode) }
90
+ function itemAtIndex(index) { return view.itemAtIndex(index) }
91
+ function contentY() { return view.contentY }
92
+ // The scrolling list itself, for the anchor that puts the view back after a re-list; see ui/js/AnchorHold.js.
93
+ readonly property alias viewport: view
94
+ // A platform drag in flight, so a slow click never renames off one; ui/ColumnsArea.qml reads it.
95
+ readonly property bool fileDragActive: dragSession.Drag.active
96
+ // Cursor keeps three rows context above and below; wheel path follows viewport margin-free; click context 0 never moves list.
97
+ function showCursor(viewIndex, context) {
98
+ // The column's own rowTotal falls back to its rows with no pane, the same fallback its model uses.
99
+ var to = ScrollOff.cursorY(view, viewIndex, root.rowTotal, Theme.fileRowHeight, context)
100
+ if (to !== null)
101
+ view.contentY = to
102
+ }
103
+ readonly property alias scrollBar: verticalScroll
104
+ function restartSettle() { settle.restart() }
105
+ function restartCoalesce() { coalesce.restart() }
106
+ function primeSettle() { settle.interval = root.pane.firstSettleMs }
107
+
108
+ function visibleRange() {
109
+ var visibleRows = Math.max(1, Math.ceil(view.height / Theme.fileRowHeight))
110
+ var fallback = Thumbs.viewport(view.contentY - view.originY, Theme.fileRowHeight, visibleRows, view.count)
111
+ if (root.pane && root.pane.renamingIndex >= 0) {
112
+ var first = view.indexAt(0, view.contentY)
113
+ var last = view.indexAt(0, view.contentY + view.height - 1)
114
+ first = first < 0 ? fallback.first : first
115
+ return {first: first, last: last < 0 ? Math.min(view.count - 1, first + visibleRows) : last}
116
+ }
117
+ return fallback
118
+ }
119
+
120
+ // The visible folder rows of a peek column that name no device, which a drag entering the pane asks the backend for.
121
+ function dropAsks() {
122
+ if (!root.visible || !root.peekSource) return []
123
+ var range = root.visibleRange()
124
+ return DropDev.folderAsks(root.rows, root.peekSource.dir, range.first, range.last, root.peekSource.pane)
125
+ }
126
+
127
+ // The active column uses List/Grid's integer model and refills only around its viewport.
128
+ function requestIfDrifted() {
129
+ if (root.pane === null || !root.visible || root.pane.listInFlight
130
+ || root.pane.total === 0 || root.pane.shown !== null)
131
+ return
132
+ var range = root.visibleRange()
133
+ var heldEnd = root.pane.held + root.pane.rows.length
134
+ if (root.pane.rows.length === 0
135
+ || (range.first - root.pane.held < root.pane.refetchMargin && root.pane.held > 0)
136
+ || (heldEnd - range.last < root.pane.refetchMargin && heldEnd < root.pane.total))
137
+ root.pane.backend.window(Math.max(0, range.first - root.pane.buffer), root.pane.windowSize)
138
+ }
139
+
140
+ // The viewport's rows and no more, rule 1: the same plan the list and the grid run, over this column's own scroll position.
141
+ function requestThumbs() {
142
+ // visible is effective visibility, so the column kept alive under another view plans nothing against the shared state.
143
+ if (root.pane === null || !root.visible || root.pane.total === 0 || root.pane.listInFlight || !root.pane.storageKnown)
144
+ return
145
+ var range = root.visibleRange()
146
+ var span = Filter.span(root.pane.shown, range.first, range.last)
147
+ var work = Filter.cut(Thumbs.plan(root.pane.thumbState, root.pane.rows, root.pane.held,
148
+ span.first, span.last, ViewState.thumbnailMode), root.pane.shown, root.pane.thumbState)
149
+ // Only the loaded preview owns an off-viewport request; manual cursor movement asks nothing extra.
150
+ work.drop = work.drop.filter(function (index) { return index !== root.pane.previewIndex })
151
+ root.pane.backend.thumbcancel(work.drop)
152
+ work.cacheOnly = ExtThumbs.cacheOnly(root.pane.storageClass, ViewState.preview)
153
+ root.pane.backend.thumb(work.ask, work.cacheOnly)
154
+ if (work.ask.length > 0) settle.interval = root.pane.settleMs
155
+ root.thumbsApplied(work)
156
+ }
157
+
158
+ // The same viewport plan the list runs, over this column's own scroll position. Only the active
159
+ // column can ask: dirsize resolves against st.listing, which a peeked row has no index in.
160
+ function requestDirSizes() {
161
+ // Folder sizes are measured only when the user asks: a ⚖️ click, see Pane.measureDirs.
162
+ return
163
+ if (root.pane === null || !root.visible || root.pane.total === 0 || root.pane.listInFlight)
164
+ return
165
+ // The active column always draws its size, so only the class gate applies here.
166
+ if (!DirSizes.wantsSizes("columns", [], root.pane.storageClass, root.pane.storageKnown))
167
+ return
168
+ var range = root.visibleRange()
169
+ var span = Filter.span(root.pane.shown, range.first, range.last)
170
+ var ask = Filter.keep(DirSizes.plan(root.pane.dirSizeState, root.pane.rows, root.pane.held,
171
+ span.first, span.last, ViewState.thumbnailMode), root.pane.shown)
172
+ if (ask.length > 0) {
173
+ root.pane.backend.dirsize(ask)
174
+ settle.interval = root.pane.settleMs
175
+ }
176
+ root.dirSizesApplied(ask)
177
+ }
178
+
179
+ Connections {
180
+ target: ViewState
181
+ function onThumbnailModeChanged() { if (root.visible) settle.restart() }
182
+ }
183
+
184
+ Timer {
185
+ id: coalesce
186
+ interval: root.pane ? root.pane.coalesceMs : 0
187
+ repeat: false
188
+ onTriggered: root.requestIfDrifted()
189
+ }
190
+
191
+ Timer {
192
+ id: settle
193
+ interval: root.pane ? root.pane.settleMs : 120
194
+ repeat: false
195
+ onTriggered: { root.requestThumbs(); root.requestDirSizes() }
196
+ }
197
+ onRowsChanged: if (root.pane !== null) settle.restart()
198
+ // A column with no pane is a peek the user is not working in, so it keeps fewer unseen rows than the pane's cacheRows: 4 (ui/Pane.qml).
199
+ readonly property int bareCacheRows: 2
200
+ // No pane yet: the column's own rows are the listing, the same fallback its model uses.
201
+ readonly property int rowTotal: root.pane ? root.pane.shownTotal : root.rows.length
202
+ // The count a hidden column keeps its rows for, -1 once another reached it; the model compares counts, so no handler order builds a row.
203
+ property int keptTotal: -1
204
+ // Where a dropped column stands: the top a new count leaves, then each cursor move contained as showCursor does.
205
+ property real heldY: 0
206
+ Component.onCompleted: root.keptTotal = root.rowTotal
207
+ onRowTotalChanged: { root.keptTotal = root.visible ? root.rowTotal : -1; root.heldY = 0 }
208
+ onVisibleChanged: {
209
+ // A dropped column builds its rows on the frame that shows it, standing where a kept one would.
210
+ if (root.visible && root.keptTotal !== root.rowTotal) {
211
+ root.keptTotal = root.rowTotal
212
+ verticalScroll.settling = true
213
+ view.contentY = view.originY + root.heldY
214
+ verticalScroll.settling = false
215
+ }
216
+ if (root.visible && root.pane !== null) { coalesce.restart(); settle.restart() }
217
+ }
218
+ onHeightChanged: if (root.visible && root.pane !== null) { coalesce.restart(); settle.restart() }
219
+
220
+ Flea.FileDrag {
221
+ id: dragSession
222
+ pane: root.pane
223
+ peekSource: root.peekSource
224
+ }
225
+
226
+ // Only the active column owns this directory; neighboring peek floors cannot target its listing.
227
+ Flea.DropInto {
228
+ anchors.fill: parent
229
+ enabled: root.pane !== null && !root.pane.trash.opened && root.pane.searchMode === ""
230
+ pane: root.pane
231
+ dest: root.pane ? root.pane.dropPath : ""
232
+ refuseLoading: DragOut.refuseLoading(root.pane && root.pane.listInFlight, false, false)
233
+ destDev: root.pane && root.pane.backend && !root.pane.listInFlight ? root.pane.backend.dirDev : 0
234
+ }
235
+
236
+ // flea-qml: every column carries the list's own titles, so the columns view (and its preview
237
+ // column) never loses them: Name in each, and on the pane's own column the ⚖️ that measures
238
+ // every folder and the Size title over the size cells. Name and Size sort as the list's do.
239
+ Item {
240
+ id: columnHeader
241
+ anchors.top: parent.top
242
+ anchors.left: parent.left
243
+ width: root.width
244
+ height: Theme.chromeHeight
245
+ // The rows keep the scroll lane clear; the titles over them keep it too, the fill spans it.
246
+ readonly property real lane: root.width - Scroll.contentWidth(root.width, Theme.spacing.rowPaddingX)
247
+ readonly property bool own: root.pane !== null && root.pane !== undefined
248
+ readonly property string sortBy: own && root.pane.backend ? root.pane.backend.sortBy : ""
249
+ readonly property bool sortDesc: own && root.pane.backend ? root.pane.backend.sortDesc : false
250
+ function title(label, key) { return columnHeader.sortBy === key ? Sort.title(label, columnHeader.sortDesc) : label }
251
+ Rectangle { anchors.fill: parent; color: Style.normalFill }
252
+ PanelSectionHeader {
253
+ id: columnName
254
+ anchors.left: parent.left
255
+ anchors.leftMargin: Theme.spacing.rowPaddingX + Theme.iconSize + Theme.spacing.gap
256
+ anchors.right: columnScale.visible ? columnScale.left : parent.right
257
+ anchors.rightMargin: columnScale.visible ? Theme.spacing.gap : columnHeader.lane + Theme.spacing.rowPaddingX
258
+ anchors.verticalCenter: parent.verticalCenter
259
+ text: columnHeader.title("Name", "name")
260
+ elide: Text.ElideRight
261
+ TapHandler { enabled: columnHeader.own; onTapped: Sort.column(root.pane, "name") }
262
+ }
263
+ Text {
264
+ id: columnScale
265
+ anchors.right: columnSize.left
266
+ anchors.rightMargin: Theme.spacing.gap
267
+ anchors.verticalCenter: parent.verticalCenter
268
+ visible: root.showsSize
269
+ text: DirSizes.UNMEASURED
270
+ textFormat: Text.PlainText
271
+ font.pixelSize: columnName.font.pixelSize
272
+ HoverHandler { cursorShape: Qt.PointingHandCursor }
273
+ TapHandler { onTapped: root.pane.measureAllDirs() }
274
+ }
275
+ PanelSectionHeader {
276
+ id: columnSize
277
+ anchors.right: parent.right
278
+ anchors.rightMargin: columnHeader.lane + Theme.spacing.rowPaddingX + Theme.spacing.gap
279
+ anchors.verticalCenter: parent.verticalCenter
280
+ visible: root.showsSize
281
+ text: columnHeader.title("Size", "size")
282
+ horizontalAlignment: Text.AlignRight
283
+ TapHandler { onTapped: Sort.column(root.pane, "size") }
284
+ }
285
+ }
286
+
287
+ ListView {
288
+ id: view
289
+ anchors.top: columnHeader.bottom
290
+ anchors.left: parent.left
291
+ anchors.right: parent.right
292
+ anchors.bottom: parent.bottom
293
+
294
+ model: Flea.StableModel { id: stable; view: view; total: root.visible || root.keptTotal === root.rowTotal ? root.rowTotal : 0; keptRows: true
295
+ warm: root.pane !== null && view.visible && root.pane.searchMode.length > 0 && root.pane.swap.searchWarm === true; warmRows: Math.floor((view.height + view.cacheBuffer) / Theme.fileRowHeight) + 1 }
296
+ clip: true
297
+ // The pane's cache rows, as ui/List.qml takes them: Qt's default 320 px builds about 12 unseen rows into every landing.
298
+ cacheBuffer: Theme.fileRowHeight * (root.pane ? root.pane.cacheRows : root.bareCacheRows)
299
+ boundsBehavior: Flickable.StopAtBounds
300
+ onContentYChanged: if (root.pane !== null) { coalesce.start(); settle.restart() }
301
+ onCountChanged: root.prebuild.landed()
302
+ // The error line's growth lands in contentHeight after layout, so the row is contained once then, never on a later scroll's estimate.
303
+ onContentHeightChanged: if (root.containRenameError) { root.containRenameError = false; view.positionViewAtIndex(root.renameViewIndex, ListView.Contain) }
304
+ reuseItems: true
305
+
306
+ // G7 needs an empty press target below the final row even when a long column fills the viewport.
307
+ footer: Item {
308
+ width: Scroll.contentWidth(view.width, Theme.spacing.rowPaddingX)
309
+ height: root.pane ? Theme.spacing.rowPaddingY : 0
310
+ }
311
+
312
+ Flea.FastScrollHandler {
313
+ parent: view
314
+ flickable: view
315
+ }
316
+
317
+ Flea.ViewportScrollBar {
318
+ id: verticalScroll
319
+ parent: view
320
+ anchors { top: parent.top; right: parent.right }
321
+ flickable: view
322
+ }
323
+
324
+ Flea.SelectionBand {
325
+ parent: view
326
+ pane: root.pane
327
+ flickable: view
328
+ }
329
+
330
+ // Empty space below the last row, the same rule ui/List.qml carries: the pane's own column answers at once while a peek navigates to its drawn directory first and opens its menu once the rows land.
331
+ TapHandler {
332
+ acceptedButtons: Qt.RightButton
333
+ onTapped: function (eventPoint) {
334
+ if (!Tap.onBackground(view, eventPoint))
335
+ return
336
+ if (root.pane !== null)
337
+ root.backgroundMenuRequested(eventPoint)
338
+ else
339
+ root.neighbourBackgroundRequested(eventPoint)
340
+ }
341
+ }
342
+
343
+ delegate: Flea.ColumnRow {
344
+ id: cell
345
+ required property int index
346
+ // Parked while pooled (ColumnRow.live): a parked value reads itself back, so parking re-runs nothing that draws.
347
+ readonly property int listingIndex: !cell.live ? -1 : root.pane ? Filter.at(root.pane.shown, index) : index
348
+ // Filed by listing row in the column's cursor mark, which sets cursor; see ui/CursorMark.qml.
349
+ property int markRow: -1
350
+ // Built ahead of a landing past the shown rows: parked hidden until the landing adopts it.
351
+ property bool prebuilt: false
352
+ Component.onCompleted: if (!root.prebuild.built(cell)) cursorMark.place(cell)
353
+ Component.onDestruction: root.prebuild.gone(cell)
354
+ ListView.onReused: root.prebuild.adoptCell(cell)
355
+ onListingIndexChanged: cursorMark.place(cell)
356
+ // Each column keeps the scroll lane clear, the same rule ui/List.qml follows.
357
+ width: Scroll.contentWidth(view.width, Theme.spacing.rowPaddingX)
358
+ paintWidth: view.width
359
+ // A shrunk listing subscripts out of range under a delegate not yet released, and QML
360
+ // hands that back as undefined; every row reader in the tree tests against a real null.
361
+ row: !cell.live ? cell.row : root.pane ? root.pane.rowFor(listingIndex) : root.rows[index] !== undefined ? root.rows[index] : null
362
+ thumb: !cell.live ? cell.thumb : root.pane !== null && Thumbs.allowed(row, ViewState.thumbnailMode) ? root.pane.thumbFor(listingIndex) : ""
363
+ showSize: root.showsSize
364
+ dirSize: !cell.live ? cell.dirSize : root.pane !== null ? DirSizes.cellFor(root.pane.dirSizeState, listingIndex) : null
365
+ pane: root.pane
366
+ // The clipboard mark is looked up only on the pane's own column, and never while it is empty.
367
+ clipMark: !cell.live ? cell.clipMark : root.clipEmpty ? "" : (root.pane !== null ? ClipMarks.markForRow(root.pane, cell.row ? cell.row.n : "", root.pane.clipboard) : "")
368
+ // The list and the grid both mark a selection member apart from the cursor; so does this.
369
+ selected: cell.live && root.pane !== null && root.pane.isSelected(listingIndex)
370
+ dropTarget: dragSession.dropIndex >= 0 && listingIndex === dragSession.dropIndex
371
+ dropCopying: dragSession.dragCopy
372
+ dropLinking: dragSession.dragLink
373
+ // Read off the normalised row above: subscripting rows again hands a shrunk listing's undefined to a bool.
374
+ lifted: !cell.live ? cell.lifted : root.liftedName.length > 0 && row !== null && row.n === root.liftedName
375
+ dim: cell.live ? root.dim && !lifted : cell.dim
376
+ // The renaming row is always the cursor row; it hides its own name under the editor, as ui/Row.qml does.
377
+ renaming: cell.cursor && root.renaming
378
+ errorGrowth: cell.cursor && root.renameErrorHeight > 0 ? Math.max(root.renameErrorHeight, renameLoader.y + renameLoader.height - root.renameTop - Theme.fileRowHeight) : 0
379
+ // The column's own budget, so no row measures its own text to elide it.
380
+ nameBudget: cell.showChevron ? root.nameBudgetChevron : root.nameBudgetPlain
381
+
382
+ TapHandler {
383
+ id: tap
384
+ acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
385
+ // A held press must still tap on release.
386
+ longPressThreshold: 0
387
+ // A press held past the interval must not fire while the button
388
+ // is still down; ColumnsArea stops the pane's timer from onRowPressed.
389
+ onPressedChanged: if (pressed) root.rowPressed(cell.listingIndex)
390
+ onTapped: function (eventPoint, button) {
391
+ if (root.pane !== null) {
392
+ if (cell.listingIndex < 0 || !cell.row) return
393
+ if (button === Qt.MiddleButton)
394
+ root.tabRequested(cell.row)
395
+ else if (button === Qt.RightButton)
396
+ root.menuRequested(cell.listingIndex, eventPoint)
397
+ else if (cell.onSizeCell(eventPoint.position)) {
398
+ if (tap.tapCount === 1) root.pane.measureDirs([cell.listingIndex])
399
+ } else
400
+ root.picked(cell.listingIndex, tap.tapCount, tap.point.modifiers, Tap.onName(cell.nameItem(), cell, eventPoint.position, false))
401
+ return
402
+ }
403
+ if (button === Qt.RightButton && root.rows[index]) {
404
+ root.neighbourMenuRequested(root.rows[index].n)
405
+ return
406
+ }
407
+ var verb = Tap.tappedColumn(root.rows[index], button, tap.tapCount)
408
+ if (verb === "openTab")
409
+ root.tabRequested(root.rows[index])
410
+ else if (verb.length > 0)
411
+ root.activated(root.rows[index].n, verb === "reveal")
412
+ }
413
+ }
414
+
415
+ Flea.RowDrag {
416
+ session: dragSession
417
+ listingIndex: cell.listingIndex
418
+ row: cell.row
419
+ }
420
+ }
421
+ }
422
+
423
+ // A denied peek answers zero rows, the exact count an empty directory answers, so a locked column draws States.dc.html's Locked tile rather than reading as an empty one.
424
+ Flea.StateMessage {
425
+ anchors.fill: parent
426
+ listingState: root.lockedMode >= 0 ? "locked" : "ready"
427
+ lockedMode: root.lockedMode
428
+ total: root.rows.length
429
+ }
430
+
431
+ // The column boundary, one per pane and never one per row; an inactive Loader builds no pane so draws none.
432
+ Flea.Divider {
433
+ anchors.right: parent.right
434
+ anchors.top: parent.top
435
+ anchors.bottom: parent.bottom
436
+ visible: root.showDivider
437
+ }
438
+
439
+ // corner: one editor for this column, never one inside each row. A delegate binding that follows
440
+ // the pane's renamingIndex costs this column its keys, measured on the box: the comma that opens
441
+ // Settings stopped reaching ui/js/Focus.js, which case_overlays catches. An overlay follows no
442
+ // delegate, so the keys are safe by construction and only the active column ever draws one.
443
+ readonly property int renameViewIndex: root.pane !== null && root.pane.renamingIndex >= 0
444
+ ? Filter.viewOf(root.pane.shown, root.pane.renamingIndex) : -1
445
+ readonly property bool renaming: root.renameViewIndex >= 0
446
+ // What ui/Pane.qml's renameEditor() hands ui/Ipc.qml, the shape a list delegate hands it.
447
+ readonly property Item editorField: renameLoader.item as Item
448
+ readonly property string editorText: renameLoader.item ? renameLoader.item.current : ""
449
+ function commitEditor() { return renameLoader.item ? renameLoader.item.commit() : false }
450
+
451
+ // The span ColumnRow draws its name in, one gap after the mark to one gap before its size cell, and nothing beyond it.
452
+ readonly property real renameLeft: Theme.spacing.rowPaddingX + Theme.iconSize + Theme.spacing.gap
453
+ // Read when the editor is built, as its name is, because rowFor answers only once the row is held.
454
+ function renamingFolder() {
455
+ var row = root.pane ? root.pane.rowFor(root.pane.renamingIndex) : null
456
+ return !!row && row.d === true
457
+ }
458
+ // The renaming row is the cursor row, so a folder carries its chevron, and the size cell sits left of it as ColumnRow anchors both.
459
+ readonly property real renameRight: Theme.spacing.rowPaddingX + (renameLoader.item !== null && root.renamingFolder() ? Theme.font.caption : 0)
460
+ + (root.showsSize ? 2 * Theme.spacing.gap + Theme.column.size : 0)
461
+ readonly property real renameWidth: Math.max(0, Scroll.contentWidth(view.width, Theme.spacing.rowPaddingX) - root.renameLeft - root.renameRight)
462
+ readonly property real renameTop: root.renameViewIndex * Theme.fileRowHeight
463
+ // The editor owns its height, one line box; the column centres it in the row on whole pixels.
464
+ readonly property real renameY: root.renameTop + Math.round((Theme.fileRowHeight - (renameLoader.item ? renameLoader.item.fieldHeight : 0)) / 2)
465
+ readonly property real renameErrorHeight: renameLoader.item ? renameLoader.item.errorHeight : 0
466
+ // Set when an error line appears or changes height, and spent by the view's next contentHeight change.
467
+ property bool containRenameError: false
468
+ onRenameErrorHeightChanged: root.containRenameError = root.renameErrorHeight > 0
469
+
470
+ Loader {
471
+ id: renameLoader
472
+ parent: view.contentItem
473
+ // Loaded only while a rename is open: a RenameField built beside every row reports its own
474
+ // hide at creation, and that hide is an abandon.
475
+ active: root.renaming
476
+ // The editor leaves focus in this ListView, which eats Up and Down, so this pane's columns area takes it back in any view.
477
+ onActiveChanged: if (!active && view.focus && root.pane && root.pane.columnsArea) root.pane.columnsArea.focus = true
478
+ x: root.renameLeft
479
+ y: root.renameY
480
+ width: root.renameWidth
481
+ z: 2
482
+ sourceComponent: Flea.RenameField {
483
+ height: implicitHeight
484
+ pane: root.pane
485
+ errorSpan: Math.max(0, root.renameWidth + root.renameRight - Theme.spacing.rowPaddingX)
486
+ name: root.pane && root.pane.rowFor(root.pane.renamingIndex)
487
+ ? String(root.pane.rowFor(root.pane.renamingIndex).n).split("/").pop() : ""
488
+ onCommitted: function (newName) { root.pane.commitRename(newName) }
489
+ onAbandoned: root.pane.renamingIndex = -1
490
+ }
491
+ }
492
+
493
+ // For ui/Ipc.qml's columnChildEmpty readers: the tile's state and its mark's box.
494
+ readonly property Item emptyItem: emptyTile
495
+ Loader {
496
+ anchors.fill: parent
497
+ active: root.loadingRows
498
+ sourceComponent: Flea.LoadingState {
499
+ heldOff: true
500
+ onShownChanged: root.loadingShown(shown)
501
+ Component.onCompleted: if (shown) root.loadingShown(true)
502
+ }
503
+ }
504
+ // The same hero the list draws, per the operator: a peeked empty directory animates like the pane's own.
505
+ Flea.EmptyState {
506
+ id: emptyTile
507
+ anchors.fill: parent
508
+ visible: root.drawsEmpty && root.rows.length === 0 && root.lockedMode < 0
509
+ }
510
+
511
+ // Cursor can move off screen through keyboard, so column follows it with context.
512
+ // Selection ensures whole row (context 0); showRow spent margin, second margin would move clicked row.
513
+ onSelectedIndexChanged: {
514
+ root.prebuild.kick()
515
+ if (root.selectedIndex < 0)
516
+ return
517
+ var at = root.pane ? Filter.viewOf(root.pane.shown, root.selectedIndex) : root.selectedIndex
518
+ if (root.visible || root.keptTotal === root.rowTotal)
519
+ root.showCursor(at, 0)
520
+ else
521
+ root.heldY = ScrollOff.containY(at * Theme.fileRowHeight, Theme.fileRowHeight, root.heldY, view.height)
522
+ }
523
+ }