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,47 @@
1
+ import QtQuick
2
+ import qs.Commons
3
+
4
+ // The bulk card's old-names column: one still row per selected name.
5
+ Column {
6
+ id: root
7
+ required property var oldNames
8
+ // The dialog's own half-width gap and stack gap, bound by the card so both halves stay equal.
9
+ required property int columnGap
10
+ required property int headGap
11
+ // How far a column's first name sits under its label: the new names box's hairline and 2 px of padding, in this column and in that box alike.
12
+ readonly property int rowsInset: Theme.spacing.hairline + 2
13
+ width: (parent.width - columnGap) / 2
14
+ spacing: headGap
15
+ Text {
16
+ text: "OLD NAMES"
17
+ color: Theme.color.muted
18
+ font.family: Theme.font.family
19
+ font.pixelSize: Theme.font.caption
20
+ textFormat: Text.PlainText
21
+ }
22
+ Column {
23
+ width: parent.width
24
+ topPadding: root.rowsInset
25
+ spacing: 0
26
+ Repeater {
27
+ model: root.oldNames
28
+ // The name centres in its row the way the new names' fields do, so both rest on the same pixel rows.
29
+ delegate: Item {
30
+ required property var modelData
31
+ required property int index
32
+ width: parent.width
33
+ height: Theme.fileRowHeight
34
+ Text {
35
+ width: parent.width
36
+ anchors.verticalCenter: parent.verticalCenter
37
+ text: parent.modelData
38
+ textFormat: Text.PlainText
39
+ elide: Text.ElideRight
40
+ color: Theme.color.muted
41
+ font.family: Theme.font.family
42
+ font.pixelSize: Theme.font.body
43
+ }
44
+ }
45
+ }
46
+ }
47
+ }
@@ -0,0 +1,380 @@
1
+ import QtQuick
2
+ import Quickshell
3
+ import Quickshell.Io
4
+ import qs.Commons
5
+ import "." as Flea
6
+ import "js/BulkRename.js" as BulkRename
7
+
8
+ // Bulk rename card: Find/Replace, one editable line per new name, live reasons, one Rename and one undo.
9
+ FocusScope {
10
+ id: root
11
+ anchors.fill: parent
12
+ visible: opened || opacity > 0
13
+ // Closed means no input, even while the fade-out is still drawn.
14
+ enabled: opened
15
+ opacity: 0
16
+ property bool opened: false
17
+ property var oldNames: []
18
+ property var newNames: []
19
+ property var sourcePaths: []
20
+ property string folder: ""
21
+ property string find: ""
22
+ property string replace: ""
23
+ property var owner: null
24
+ // The board's 640 card, so a narrower window clamps it rather than clipping it.
25
+ readonly property real cardWant: 640
26
+ // The card's own padding, matching the 16 the buttons row and title already assume.
27
+ readonly property int cardPadding: 16
28
+ // 255 name bytes plus one newline per selected name, the TUI batch's own bound.
29
+ readonly property int nameLineBytes: 256
30
+ // The two half-width columns share one gap, so both halves measure the same remainder.
31
+ readonly property int columnGap: 14
32
+ // The new-names stack breathes less than a column gap, the way the old-names one does.
33
+ readonly property int stackGap: 4
34
+ // The names frame's sides, wider than its top and bottom for the caret; those take the old column's rowsInset.
35
+ readonly property int frameSide: 8
36
+ // A new name and its reason sit one side-inset apart.
37
+ readonly property int reasonGap: 8
38
+ // The mktemp leaf's fixed stem, so the cleanup guard measures the template it cleans.
39
+ readonly property string scratchStem: "flea-rename-"
40
+ property string terminalBase: ""
41
+ property string terminalDir: ""
42
+ property string terminalFile: ""
43
+ property bool terminalActive: false
44
+ property string terminalError: ""
45
+ readonly property var cardItem: card
46
+ // The model is a count; edits mutate one element and bump namesVersion, so a keystroke never rebuilds rows or steals the caret.
47
+ property int namesVersion: 0
48
+ property int focusedLine: -1
49
+ readonly property var allReasons: { root.namesVersion; return BulkRename.reasons(root.newNames) }
50
+ readonly property var counts: BulkRename.counts(root.oldNames, root.newNames, root.allReasons)
51
+ readonly property string footerText: BulkRename.footer(counts.renamed, counts.unchanged, counts.invalid)
52
+ readonly property string renameText: BulkRename.renameLabel(counts.renamed)
53
+ readonly property bool canRename: root.opened && counts.invalid === 0 && counts.renamed > 0
54
+ // The control holding the keyboard, so the capture case asserts Tab order without OCR.
55
+ readonly property string focusedControl: editButton.activeFocus ? "Edit in terminal"
56
+ : cancelButton.activeFocus ? "Cancel" : renameButton.activeFocus ? "Rename"
57
+ : findField.focused ? "Find" : replaceField.focused ? "Replace"
58
+ : namesScope.activeFocus && root.focusedLine >= 0 ? "line " + (root.focusedLine + 1) : ""
59
+ // Every Tab stop routes through the pure order in BulkRename.js, so Shift+Tab walks back the same way.
60
+ function stepFocus(current, back) {
61
+ var stop = BulkRename.nextStop(current, back, root.oldNames.length)
62
+ var why = back ? Qt.BacktabFocusReason : Qt.TabFocusReason
63
+ if (stop === "find") findField.takeFocus()
64
+ else if (stop === "replace") replaceField.takeFocus()
65
+ else if (stop === "edit") editButton.forceActiveFocus(why)
66
+ else if (stop === "cancel") cancelButton.forceActiveFocus(why)
67
+ else if (stop === "rename") renameButton.forceActiveFocus(why)
68
+ else root.focusNameLine(Number(stop.substring(5)) - 1, why)
69
+ }
70
+ // Return/Up/Down move the caret between name lines, stopping at the ends, as a text editor's lines do.
71
+ function focusNameLine(index, why, col) { if (index >= 0 && index < nameLines.count) nameLines.itemAt(index).takeFocus(why, col) }
72
+ function reasonAt(index) { return index < root.allReasons.length ? root.allReasons[index] : "" }
73
+ function changedAt(index) { root.namesVersion; return String(root.newNames[index]) !== String(root.oldNames[index]) }
74
+ function open(paths, holder) {
75
+ owner = holder
76
+ sourcePaths = paths.slice()
77
+ folder = String(paths[0]).substring(0, String(paths[0]).lastIndexOf("/")) || "/"
78
+ oldNames = paths.map(function (p) { return String(p).substring(String(p).lastIndexOf("/") + 1) })
79
+ newNames = oldNames.slice()
80
+ find = ""
81
+ replace = ""
82
+ terminalBase = ""
83
+ terminalDir = ""
84
+ terminalFile = ""
85
+ terminalActive = false
86
+ terminalError = ""
87
+ opened = true
88
+ findField.takeFocus()
89
+ }
90
+ function close() {
91
+ if (terminalActive) cleanupTerminal()
92
+ opened = false
93
+ if (owner) owner.forceActiveFocus()
94
+ }
95
+ function applyFind() {
96
+ newNames = BulkRename.applyFindReplace(root.oldNames, root.find, root.replace)
97
+ }
98
+ function commit() {
99
+ if (!root.canRename) return
100
+ var backend = owner.backend
101
+ var paths = root.sourcePaths.slice()
102
+ var names = root.newNames.slice()
103
+ root.close()
104
+ backend.bulkRename(paths, names)
105
+ }
106
+ // Edit in terminal: names go to a private mktemp dir, $EDITOR opens the file, and the card reads it back on exit.
107
+ function editInTerminal() {
108
+ root.terminalError = ""
109
+ if (root.terminalActive) root.cleanupTerminal()
110
+ root.terminalBase = Quickshell.env("TMPDIR") || "/tmp"
111
+ mktemp.command = ["mktemp", "-d", root.terminalBase + "/" + root.scratchStem + "XXXXXX"]
112
+ mktemp.running = true
113
+ }
114
+ // $EDITOR over the names file in a terminal through xdg-terminal-exec, the file riding as argv and never in the shell string.
115
+ function launchEditor() {
116
+ var editor = Quickshell.env("VISUAL") || Quickshell.env("EDITOR") || ""
117
+ if (!editor || editChild.running) {
118
+ root.terminalError = "Bulk rename could not open an editor."
119
+ return
120
+ }
121
+ editChild.command = ["xdg-terminal-exec", "--dir=" + root.folder, "--",
122
+ "/bin/sh", "-c", "exec " + editor + " \"$1\"", "flea-bulk-rename", root.terminalFile]
123
+ editChild.running = true
124
+ }
125
+ // A scratch dir is the base plus one flea-rename leaf, so a cleanup never walks elsewhere.
126
+ function isScratchDir(dir) {
127
+ if (terminalBase.length === 0 || dir.length <= terminalBase.length + root.scratchStem.length + 1) return false
128
+ if (dir.substring(0, terminalBase.length + 1) !== terminalBase + "/") return false
129
+ var leaf = dir.substring(terminalBase.length + 1)
130
+ if (leaf.indexOf("/") >= 0 || leaf.indexOf("..") >= 0) return false
131
+ return leaf.substring(0, root.scratchStem.length) === root.scratchStem
132
+ }
133
+ // Sample input: "first.png\nsecond.png\n", one name per line with a single trailing newline.
134
+ function reloadTerminal() {
135
+ terminalFileView.reload()
136
+ terminalFileView.waitForJob()
137
+ var text = terminalFileView.text()
138
+ if (text.length > root.oldNames.length * root.nameLineBytes) {
139
+ terminalError = "Bulk rename refused: the edited names exceed the filename limits."
140
+ return
141
+ }
142
+ var lines = String(text).split("\n")
143
+ if (lines.length > 0 && lines[lines.length - 1] === "") lines.pop()
144
+ if (lines.length !== root.oldNames.length) {
145
+ terminalError = "Bulk rename refused: the number of names changed."
146
+ return
147
+ }
148
+ terminalError = ""
149
+ newNames = lines
150
+ }
151
+ function cleanupTerminal() {
152
+ terminalActive = false
153
+ if (root.terminalDir.length > 0 && isScratchDir(root.terminalDir)) {
154
+ cleanup.command = ["rm", "-rf", root.terminalDir]
155
+ cleanup.running = true
156
+ }
157
+ terminalDir = ""
158
+ terminalFile = ""
159
+ }
160
+ Keys.onPressed: function (event) {
161
+ if (event.key === Qt.Key_Escape) { root.close(); event.accepted = true; return }
162
+ if (event.key === Qt.Key_Tab || event.key === Qt.Key_Backtab) { event.accepted = true; return }
163
+ if (event.modifiers & (Qt.ControlModifier | Qt.AltModifier | Qt.MetaModifier)) { event.accepted = true; return }
164
+ event.accepted = true
165
+ }
166
+ Flea.Reveal { target: root; shown: root.opened; lift: card }
167
+ Process {
168
+ id: mktemp
169
+ stderr: StdioCollector { waitForEnd: true }
170
+ stdout: StdioCollector { waitForEnd: true }
171
+ onExited: function (code) {
172
+ var dir = String(mktemp.stdout.text).trim()
173
+ if (!root.opened) {
174
+ if (code === 0 && root.isScratchDir(dir)) { cleanup.command = ["rm", "-rf", dir]; cleanup.running = true }
175
+ return
176
+ }
177
+ if (code !== 0 || !root.isScratchDir(dir)) { root.terminalError = "Bulk rename could not make its edit directory."; return }
178
+ root.terminalDir = dir
179
+ root.terminalFile = dir + "/names"
180
+ // The file is created at 0600 here, so the editor's own save keeps it private.
181
+ prime.command = ["install", "-m", "0600", "/dev/null", root.terminalFile]
182
+ prime.running = true
183
+ }
184
+ }
185
+ // install names the mode at creation, the way the TUI batch's exclusive create does.
186
+ Process {
187
+ id: prime
188
+ onExited: function (code) {
189
+ if (!root.opened) { root.cleanupTerminal(); return }
190
+ if (code !== 0) { root.terminalError = "Bulk rename could not make its edit file."; root.cleanupTerminal(); return }
191
+ terminalFileView.path = root.terminalFile
192
+ terminalFileView.setText(root.newNames.join("\n") + "\n")
193
+ terminalFileView.waitForJob()
194
+ root.terminalActive = true
195
+ root.launchEditor()
196
+ }
197
+ }
198
+ Process {
199
+ id: editChild
200
+ onExited: function (code) {
201
+ if (!root.terminalActive) return
202
+ if (code === 0) root.reloadTerminal()
203
+ else root.terminalError = "Bulk rename could not open an editor."
204
+ }
205
+ }
206
+ Process {
207
+ id: cleanup
208
+ }
209
+ FileView {
210
+ id: terminalFileView
211
+ watchChanges: root.terminalActive
212
+ onFileChanged: if (root.terminalActive) root.reloadTerminal()
213
+ }
214
+ Connections {
215
+ target: findField.input
216
+ function onTextChanged() { root.find = findField.input.text; root.applyFind() }
217
+ }
218
+ Connections {
219
+ target: replaceField.input
220
+ function onTextChanged() { root.replace = replaceField.input.text; root.applyFind() }
221
+ }
222
+ Flea.DialogScrim {
223
+ onDismissed: root.close()
224
+ }
225
+ Rectangle {
226
+ id: card
227
+ x: Theme.cardOrigin(root.width, width)
228
+ y: Theme.cardOrigin(root.height, height)
229
+ width: Theme.cardSpan(root.cardWant, root.width - 2 * Theme.spacing.gap)
230
+ height: Theme.cardSpan(body.wanted + 2 * root.cardPadding + 2 * Theme.spacing.hairline, root.height - 2 * Theme.spacing.gap)
231
+ color: Theme.color.surface
232
+ border.color: Theme.color.mutedFrame
233
+ border.width: Theme.spacing.hairline
234
+ radius: Style.cornerRadius
235
+ MouseArea {
236
+ anchors.fill: parent
237
+ hoverEnabled: true
238
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
239
+ onWheel: function (wheel) { wheel.accepted = true }
240
+ }
241
+ Flea.CardFrame {
242
+ id: body
243
+ bleed: Theme.focusClearance
244
+ anchors.fill: parent
245
+ anchors.leftMargin: root.cardPadding + Theme.spacing.hairline - Theme.focusClearance
246
+ anchors.rightMargin: root.cardPadding + Theme.spacing.hairline - Theme.focusClearance
247
+ anchors.topMargin: root.cardPadding + Theme.spacing.hairline - Theme.focusClearance
248
+ anchors.bottomMargin: root.cardPadding + Theme.spacing.hairline - Theme.focusClearance
249
+ title: Flea.DialogTitle { width: parent.width; text: BulkRename.title(root.oldNames.length) }
250
+ buttons: Row {
251
+ anchors.right: parent.right
252
+ spacing: Theme.spacing.gap
253
+ // Tab reaches every button, the BulkRename board's callout 6: Qt's chain skips a button without activeFocusOnTab.
254
+ Flea.DialogButton { id: editButton; label: "Edit in terminal"; activeFocusOnTab: true; tabHandle: true; onTabbed: function (from, back) { root.stepFocus("edit", back) }; onActivated: root.editInTerminal() }
255
+ Flea.DialogButton { id: cancelButton; label: "Cancel"; activeFocusOnTab: true; tabHandle: true; onTabbed: function (from, back) { root.stepFocus("cancel", back) }; onActivated: root.close() }
256
+ Flea.DialogButton { id: renameButton; label: root.renameText; primary: true; available: root.canRename; activeFocusOnTab: true; tabHandle: true; onTabbed: function (from, back) { root.stepFocus("rename", back) }; onActivated: root.commit() }
257
+ }
258
+ Column {
259
+ width: parent.width
260
+ spacing: Theme.spacing.gap
261
+ Row {
262
+ width: parent.width
263
+ spacing: root.columnGap
264
+ Flea.DialogField {
265
+ id: findField
266
+ width: (parent.width - root.columnGap) / 2
267
+ label: "Find"
268
+ onAccepted: root.commit()
269
+ // A field reports Tab instead of moving, so the card keeps the keyboard inside itself.
270
+ onTabbed: function (from, back) { root.stepFocus("find", back) }
271
+ }
272
+ Flea.DialogField {
273
+ id: replaceField
274
+ width: (parent.width - root.columnGap) / 2
275
+ label: "Replace"
276
+ onAccepted: root.commit()
277
+ onTabbed: function (from, back) { root.stepFocus("replace", back) }
278
+ }
279
+ }
280
+ Row {
281
+ width: parent.width
282
+ spacing: root.columnGap
283
+ Flea.BulkOldNames {
284
+ id: oldColumn
285
+ oldNames: root.oldNames
286
+ columnGap: root.columnGap
287
+ headGap: root.stackGap
288
+ }
289
+ Column {
290
+ width: (parent.width - root.columnGap) / 2
291
+ spacing: root.stackGap
292
+ Text {
293
+ text: "NEW NAMES"
294
+ color: Theme.color.muted
295
+ font.family: Theme.font.family
296
+ font.pixelSize: Theme.font.caption
297
+ textFormat: Text.PlainText
298
+ }
299
+ Rectangle {
300
+ id: namesBox
301
+ width: parent.width
302
+ color: Theme.color.background
303
+ // One editor, so the frame follows the caret however many lines it holds.
304
+ border.color: namesScope.activeFocus ? Theme.color.accent : Theme.color.mutedFrame
305
+ border.width: Theme.spacing.hairline
306
+ height: root.oldNames.length * Theme.fileRowHeight + 2 * oldColumn.rowsInset
307
+ // One focus scope around the name lines, so the frame binds live focus state with no counter to drift.
308
+ FocusScope {
309
+ id: namesScope
310
+ anchors.fill: parent
311
+ anchors.topMargin: oldColumn.rowsInset
312
+ anchors.bottomMargin: oldColumn.rowsInset
313
+ anchors.leftMargin: root.frameSide
314
+ anchors.rightMargin: root.frameSide
315
+ Column {
316
+ anchors.fill: parent
317
+ spacing: 0
318
+ Repeater {
319
+ id: nameLines
320
+ model: root.oldNames.length
321
+ delegate: Row {
322
+ id: nameRow
323
+ required property int index
324
+ function takeFocus(why, col) { if (col !== undefined) nameField.cursorPosition = Math.min(col, nameField.length); nameField.forceActiveFocus(why) }
325
+ width: parent.width
326
+ height: Theme.fileRowHeight
327
+ spacing: root.reasonGap
328
+ TextInput {
329
+ id: nameField
330
+ width: parent.width - reason.width - parent.spacing
331
+ anchors.verticalCenter: parent.verticalCenter
332
+ text: BulkRename.nameAt(root.newNames, nameRow.index)
333
+ color: root.reasonAt(nameRow.index) ? Theme.color.errorOnSurface
334
+ : root.changedAt(nameRow.index) ? Theme.color.foreground : Theme.color.muted
335
+ selectionColor: Theme.color.accent
336
+ font.family: Theme.font.family
337
+ font.pixelSize: Theme.font.body
338
+ clip: true
339
+ onActiveFocusChanged: if (activeFocus) root.focusedLine = nameRow.index
340
+ Keys.onTabPressed: function (event) { root.stepFocus("line " + (nameRow.index + 1), false); event.accepted = true }
341
+ Keys.onBacktabPressed: function (event) { root.stepFocus("line " + (nameRow.index + 1), true); event.accepted = true }
342
+ onTextChanged: {
343
+ if (root.newNames[nameRow.index] === nameField.text) return
344
+ root.newNames[nameRow.index] = nameField.text
345
+ root.namesVersion++
346
+ }
347
+ Keys.onReturnPressed: function (event) { root.focusNameLine(nameRow.index + 1, Qt.OtherFocusReason); event.accepted = true }
348
+ Keys.onEnterPressed: function (event) { root.focusNameLine(nameRow.index + 1, Qt.OtherFocusReason); event.accepted = true }
349
+ Keys.onUpPressed: function (event) { root.focusNameLine(nameRow.index - 1, Qt.OtherFocusReason, nameField.cursorPosition); event.accepted = true }
350
+ Keys.onDownPressed: function (event) { root.focusNameLine(nameRow.index + 1, Qt.OtherFocusReason, nameField.cursorPosition); event.accepted = true }
351
+ }
352
+ Text {
353
+ id: reason
354
+ anchors.verticalCenter: parent.verticalCenter
355
+ text: root.reasonAt(nameRow.index)
356
+ textFormat: Text.PlainText
357
+ color: Theme.color.errorOnSurface
358
+ font.family: Theme.font.family
359
+ font.pixelSize: Theme.font.caption
360
+ }
361
+ }
362
+ }
363
+ }
364
+ }
365
+ }
366
+ }
367
+ }
368
+ Text {
369
+ width: parent.width
370
+ text: root.terminalError.length > 0 ? root.terminalError : root.footerText
371
+ textFormat: Text.PlainText
372
+ elide: Text.ElideRight
373
+ color: root.terminalError.length > 0 ? Theme.color.errorOnSurface : Theme.color.foreground
374
+ font.family: Theme.font.family
375
+ font.pixelSize: Theme.font.caption
376
+ }
377
+ }
378
+ }
379
+ }
380
+ }
@@ -0,0 +1,67 @@
1
+ import QtQuick
2
+ import "." as Flea
3
+
4
+ // A dialog card's inner layout: the title and the button row stay pinned, and only the body between them scrolls (ui/CardScroll.qml).
5
+ Item {
6
+ id: root
7
+
8
+ // The body is the default slot; the title and the button row stand outside the scroll.
9
+ default property alias content: scroll.content
10
+ property alias title: titleHolder.data
11
+ property alias buttons: buttonHolder.data
12
+ // The gap between the parts, the gap the single column kept between its children.
13
+ property real spacing: Theme.spacing.gap
14
+ // Room kept inside the clip, past each control's own frame, as CardScroll keeps it.
15
+ property int bleed: 0
16
+ property int bleedX: bleed
17
+ property int bleedY: bleed
18
+ property real revealClearY: 0
19
+
20
+ // What the three parts want together, for the card to clamp against the window.
21
+ readonly property real wanted: root.titleHeight + root.gapAfterTitle + scroll.wanted + root.gapBeforeButtons + root.buttonsHeight
22
+ readonly property real holderWidth: root.width - 2 * root.bleedX
23
+ property alias contentY: scroll.contentY
24
+ readonly property alias contentHeight: scroll.contentHeight
25
+ readonly property alias scrollItem: scroll
26
+ readonly property real titleHeight: titleHolder.childrenRect.height
27
+ readonly property real buttonsHeight: buttonHolder.childrenRect.height
28
+ // A part with no height takes no gap, as an invisible child of the column did.
29
+ readonly property real gapAfterTitle: root.titleHeight > 0 && (scroll.wanted > 0 || root.buttonsHeight > 0) ? root.spacing : 0
30
+ readonly property real gapBeforeButtons: root.buttonsHeight > 0 && scroll.wanted > 0 ? root.spacing : 0
31
+ // The body's room: what the card leaves between the pinned parts, never more than the body wants.
32
+ readonly property real bodyHeight: Math.max(0, Math.min(scroll.wanted,
33
+ root.height - 2 * root.bleedY - root.titleHeight - root.gapAfterTitle - root.gapBeforeButtons - root.buttonsHeight))
34
+
35
+ function reveal(item) { scroll.reveal(item) }
36
+ function holds(item) { return scroll.holds(item) }
37
+ function resetSteps() { scroll.resetSteps() }
38
+
39
+ Item {
40
+ id: titleHolder
41
+ objectName: "cardTitle"
42
+ x: root.bleedX
43
+ y: root.bleedY
44
+ width: root.holderWidth
45
+ height: root.titleHeight
46
+ }
47
+
48
+ Flea.CardScroll {
49
+ id: scroll
50
+ x: 0
51
+ y: root.titleHeight + root.gapAfterTitle
52
+ width: root.width
53
+ height: root.bodyHeight + 2 * root.bleedY
54
+ bleedX: root.bleedX
55
+ bleedY: root.bleedY
56
+ revealClearY: root.revealClearY
57
+ }
58
+
59
+ Item {
60
+ id: buttonHolder
61
+ objectName: "cardButtons"
62
+ x: root.bleedX
63
+ y: root.bleedY + root.titleHeight + root.gapAfterTitle + root.bodyHeight + root.gapBeforeButtons
64
+ width: root.holderWidth
65
+ height: root.buttonsHeight
66
+ }
67
+ }
@@ -0,0 +1,79 @@
1
+ import QtQuick
2
+ import "." as Flea
3
+
4
+ // A card body taller than the window: this viewport clamps to the card and scrolls the rest by wheel,
5
+ // touchpad, keys and focus moves, with no bar and no lane, since a card never lists files.
6
+ Flickable {
7
+ id: root
8
+
9
+ default property alias content: holder.data
10
+ // What the content wants, for the card to clamp against the window.
11
+ readonly property real wanted: holder.childrenRect.height
12
+ // Menus step the highlight instead of pixel scrolling: one row a notch through stepBy, one
13
+ // row per stepRowHeight of gained touchpad travel, with no tail. See FastScrollHandler.
14
+ property bool highlightSteps: false
15
+ property real stepRowHeight: Theme.rowHeight
16
+ property var stepBy: null
17
+ // Room kept inside the clip on every side, past each control's own frame; callers grow their margins by the same, so nothing moves.
18
+ property int bleed: 0
19
+ // The two axes apart, for a body whose rows already run to the card's side edges.
20
+ property int bleedX: bleed
21
+ property int bleedY: bleed
22
+ // Room reveal() keeps between the row and a clip edge an overlay fade covers while more content lies past it; the content's own ends clamp it away.
23
+ property real revealClearY: 0
24
+ // The holder's drawn width, so a probe reads it without walking children.
25
+ readonly property real holderWidth: holder.width
26
+
27
+ clip: true
28
+ contentWidth: width
29
+ contentHeight: root.wanted + 2 * root.bleedY
30
+ boundsBehavior: Flickable.StopAtBounds
31
+ // A highlight-stepped menu follows through reveal(); the Flickable takes no wheel itself.
32
+ interactive: !root.highlightSteps
33
+
34
+ // Tab into a field below the fold scrolls it into view with bleedY of clearance, so a form is never typed into blind and a focus frame is never cut; the ends clamp to the content.
35
+ function reveal(item) {
36
+ if (!item || root.contentHeight <= root.height || !root.holds(item))
37
+ return
38
+ var y = item.mapToItem(root.contentItem, 0, 0).y
39
+ var top = y - root.bleedY - root.revealClearY
40
+ var bottom = y + item.height + root.bleedY + root.revealClearY
41
+ if (top < root.contentY)
42
+ root.contentY = Math.max(0, top)
43
+ else if (bottom > root.contentY + root.height)
44
+ root.contentY = Math.min(root.contentHeight - root.height, bottom - root.height)
45
+ }
46
+
47
+ function holds(item) {
48
+ for (var it = item; it; it = it.parent) {
49
+ if (it === holder)
50
+ return true
51
+ }
52
+ return false
53
+ }
54
+
55
+ Connections {
56
+ target: root.Window.window
57
+ function onActiveFocusItemChanged() { root.reveal(root.Window.window.activeFocusItem) }
58
+ }
59
+
60
+ Flea.FastScrollHandler {
61
+ id: wheel
62
+ parent: root
63
+ flickable: root
64
+ stepMode: root.highlightSteps
65
+ stepRowHeight: root.stepRowHeight
66
+ stepBy: root.stepBy
67
+ }
68
+
69
+ // Drops every wheel remainder, so a menu opening never spends the last one's travel.
70
+ function resetSteps() { wheel.resetSteps() }
71
+
72
+ Item {
73
+ id: holder
74
+ // No lane: rows fill to the frame's padding on every surface using this.
75
+ x: root.bleedX
76
+ y: root.bleedY
77
+ width: Math.max(0, root.width - 2 * root.bleedX)
78
+ }
79
+ }
@@ -0,0 +1,73 @@
1
+ import QtQuick
2
+ import "." as Flea
3
+
4
+ // The one checkbox every surface draws, Containers rule 14. The box is the control and every member
5
+ // wears it; state is filled against empty, so no palette has to separate accent from foreground.
6
+ Item {
7
+ id: root
8
+
9
+ // "off", "on", or "some", which is a group heading's state and never a row's.
10
+ property string value: "off"
11
+ // Availability is not an off value: an unavailable box keeps whatever it holds and dims.
12
+ property bool available: true
13
+ // The keyboard turns an empty box's own frame foreground; a filled box, whose frame is already foreground, gains the keyline below.
14
+ property bool focused: false
15
+
16
+ readonly property bool filled: root.value !== "off"
17
+ // The board's mixed bar is 8 x 2 in an 18 px box, and the box scales from bodySmall 13 as its check does.
18
+ readonly property int barBaseWidth: 8
19
+ readonly property int barBaseHeight: 2
20
+ readonly property real boxScale: Theme.font.bodySmall / 13
21
+ readonly property Item barItem: bar
22
+ readonly property Item frameItem: frame
23
+ readonly property int borderWidth: 2 * Theme.spacing.hairline
24
+
25
+ // A 14px interior inside two 2px borders, so 18px outer at bodySmall 13.
26
+ implicitHeight: Math.round(14 * Theme.font.bodySmall / 13) + 2 * root.borderWidth
27
+ implicitWidth: root.implicitHeight
28
+ opacity: root.available ? 1 : Theme.disabledOpacity
29
+
30
+ Accessible.role: Accessible.CheckBox
31
+ Accessible.checked: root.value === "on"
32
+
33
+ Rectangle {
34
+ id: frame
35
+ anchors.fill: parent
36
+ color: root.filled ? Theme.color.foreground : "transparent"
37
+ border.width: root.borderWidth
38
+ border.color: root.filled || root.focused ? Theme.color.foreground : Theme.color.mutedFrame
39
+
40
+ // The mark is the fill cut away, so the control needs no third colour and no accent at all.
41
+ Flea.Glyph {
42
+ anchors.centerIn: parent
43
+ width: Theme.font.bodySmall * 10 / 13
44
+ height: width
45
+ strokeWidth: 3
46
+ visible: root.value === "on"
47
+ name: "check"
48
+ color: Theme.color.background
49
+ }
50
+
51
+ // A mixed box cuts the board's bar, a rectangle on whole pixels and not a glyph stroke spread over two rows.
52
+ Rectangle {
53
+ id: bar
54
+ width: Math.round(root.barBaseWidth * root.boxScale)
55
+ height: Math.max(1, Math.round(root.barBaseHeight * root.boxScale))
56
+ x: Math.round((parent.width - width) / 2)
57
+ y: Math.round((parent.height - height) / 2)
58
+ visible: root.value === "some"
59
+ color: Theme.color.background
60
+ }
61
+ }
62
+
63
+ // A focused filled box shows a foreground hairline past a one-hairline gap outside its frame; an empty box draws focus in its frame.
64
+ Rectangle {
65
+ objectName: "checkRing"
66
+ anchors.fill: parent
67
+ anchors.margins: -2 * Theme.spacing.hairline
68
+ color: "transparent"
69
+ border.width: Theme.spacing.hairline
70
+ border.color: Theme.color.foreground
71
+ visible: root.focused && root.filled
72
+ }
73
+ }