flea-qml 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (637) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +511 -2
  3. package/THIRD-PARTY-NOTICES.md +29 -0
  4. package/demos/App.java +5 -0
  5. package/demos/Dockerfile +4 -0
  6. package/demos/Main.kt +3 -0
  7. package/demos/Program.cs +1 -0
  8. package/demos/README.md +12 -0
  9. package/demos/app.dart +3 -0
  10. package/demos/app.deb +0 -0
  11. package/demos/app.js +1 -0
  12. package/demos/backup.tar +0 -0
  13. package/demos/budget.xlsx +0 -0
  14. package/demos/build.sh +2 -0
  15. package/demos/bundle.zip +0 -0
  16. package/demos/clip.mp4 +0 -0
  17. package/demos/data.sqlite +0 -0
  18. package/demos/disk.iso +0 -0
  19. package/demos/engine.cpp +5 -0
  20. package/demos/firmware.bin +0 -0
  21. package/demos/flake.nix +4 -0
  22. package/demos/folder/inside.txt +1 -0
  23. package/demos/font.ttf +0 -0
  24. package/demos/index.html +5 -0
  25. package/demos/index.php +2 -0
  26. package/demos/init.lua +1 -0
  27. package/demos/letter.docx +0 -0
  28. package/demos/lib.rs +3 -0
  29. package/demos/main.c +6 -0
  30. package/demos/main.h +3 -0
  31. package/demos/math-and-diagrams.md +200 -0
  32. package/demos/notes.tar.gz +0 -0
  33. package/demos/notes.txt +3 -0
  34. package/demos/photo.png +0 -0
  35. package/demos/program +2 -0
  36. package/demos/report.pdf +32 -0
  37. package/demos/script.py +1 -0
  38. package/demos/server.go +7 -0
  39. package/demos/settings.json +4 -0
  40. package/demos/slides.pptx +0 -0
  41. package/demos/song.mp3 +0 -0
  42. package/demos/style.css +4 -0
  43. package/demos/tool.rb +1 -0
  44. package/demos/types.ts +2 -0
  45. package/docs/pele.md +23 -0
  46. package/docs/protocol.md +3420 -0
  47. package/docs/temml.md +63 -0
  48. package/index.js +107 -0
  49. package/package.json +34 -4
  50. package/src/archive.js +407 -0
  51. package/src/archiveops.js +728 -0
  52. package/src/backend.js +369 -0
  53. package/src/bulkrename.js +95 -0
  54. package/src/clip-host.js +76 -0
  55. package/src/clip.js +462 -0
  56. package/src/code.js +168 -0
  57. package/src/compare.js +74 -0
  58. package/src/create.js +128 -0
  59. package/src/dirsize.js +147 -0
  60. package/src/figure-svg.js +530 -0
  61. package/src/figure-thread.js +23 -0
  62. package/src/figure.js +132 -0
  63. package/src/find.js +55 -0
  64. package/src/flea.js +39 -0
  65. package/src/fsinfo.js +39 -0
  66. package/src/highlight.js +141 -0
  67. package/src/html.js +52 -0
  68. package/src/kinds.js +89 -0
  69. package/src/listing.js +130 -0
  70. package/src/markdown-html.js +317 -0
  71. package/src/mathml.js +186 -0
  72. package/src/menu.js +180 -0
  73. package/src/meta.js +135 -0
  74. package/src/office.js +810 -0
  75. package/src/order.js +100 -0
  76. package/src/peek.js +49 -0
  77. package/src/pele-wrapper.js +695 -0
  78. package/src/permissions.js +180 -0
  79. package/src/places.js +313 -0
  80. package/src/preview-language.js +10 -0
  81. package/src/terminal-server.js +95 -0
  82. package/src/terminal-shell.js +26 -0
  83. package/src/transfer.js +669 -0
  84. package/src/trash-record.js +41 -0
  85. package/src/trash.js +210 -0
  86. package/src/trashbrowse.js +327 -0
  87. package/src/uistate.js +393 -0
  88. package/src/uistore.js +168 -0
  89. package/src/vendor/LICENSES/Apache-2.0.txt +202 -0
  90. package/src/vendor/LICENSES/MIT-katex-2015.txt +27 -0
  91. package/src/vendor/LICENSES/MIT-katex.txt +21 -0
  92. package/src/vendor/LICENSES/MIT-mermaid.txt +21 -0
  93. package/src/vendor/LICENSES/MIT-pele.txt +40 -0
  94. package/src/vendor/LICENSES/MIT-perseus.txt +18 -0
  95. package/src/vendor/LICENSES/MIT-temml.txt +21 -0
  96. package/src/vendor/pele.js +145 -0
  97. package/src/vendor/temml.mjs +14708 -0
  98. package/src/watch.js +98 -0
  99. package/src/wayland/client.js +109 -0
  100. package/src/wayland/protocol.js +55 -0
  101. package/src/wayland/protocols/ext-data-control-v1.xml +276 -0
  102. package/src/wayland/protocols/wayland.xml +3248 -0
  103. package/src/wayland/protocols/wlr-data-control-unstable-v1.xml +278 -0
  104. package/src/wayland/resource-io.js +6 -0
  105. package/src/wayland/socket-discovery.js +26 -0
  106. package/src/wayland/transport-posix.js +120 -0
  107. package/src/wayland/transport-win32.js +11 -0
  108. package/src/wayland/transport.js +3 -0
  109. package/src/wayland/win32-resources.js +80 -0
  110. package/src/wayland/win32-wire.js +62 -0
  111. package/test/archive.test.js +80 -0
  112. package/test/bench-markdown-scroll.mjs +190 -0
  113. package/test/clip-host.test.js +113 -0
  114. package/test/code-preview.test.js +35 -0
  115. package/test/compare-ui-paths.test.js +24 -0
  116. package/test/compare.test.js +54 -0
  117. package/test/delete-trash.test.js +67 -0
  118. package/test/dirsize.test.js +138 -0
  119. package/test/file-ops.test.js +307 -0
  120. package/test/file-url.test.js +24 -0
  121. package/test/find-contents.test.js +161 -0
  122. package/test/find-input.test.js +66 -0
  123. package/test/fixtures/pele-parity.json +1006 -0
  124. package/test/highlight-launcher.test.js +35 -0
  125. package/test/html-preview.test.js +22 -0
  126. package/test/input.test.js +15 -0
  127. package/test/keymap.test.js +26 -0
  128. package/test/language-icons.test.js +36 -0
  129. package/test/launcher.test.js +51 -0
  130. package/test/manual-archive-here-ui.mjs +47 -0
  131. package/test/manual-code-scroll.mjs +28 -0
  132. package/test/manual-column-scroll.mjs +24 -0
  133. package/test/manual-compare-ui.mjs +20 -0
  134. package/test/manual-find-status.mjs +37 -0
  135. package/test/manual-folder-focus.mjs +63 -0
  136. package/test/manual-html-security.mjs +23 -0
  137. package/test/manual-html-ui.mjs +30 -0
  138. package/test/manual-syntax-preview.mjs +26 -0
  139. package/test/manual-terminal-lifecycle.mjs +42 -0
  140. package/test/manual-terminal-navigation.mjs +48 -0
  141. package/test/manual-terminal-ui.mjs +47 -0
  142. package/test/manual-trash-ui.mjs +86 -0
  143. package/test/markdown-diagrams.test.js +93 -0
  144. package/test/markdown-html.test.js +105 -0
  145. package/test/mathml.test.js +92 -0
  146. package/test/menu-transfer.test.js +57 -0
  147. package/test/office-preview.test.js +154 -0
  148. package/test/pele-parity.test.js +28 -0
  149. package/test/places.test.js +134 -0
  150. package/test/preview-keys.test.js +60 -0
  151. package/test/preview-language.test.js +22 -0
  152. package/test/status-filename.test.js +20 -0
  153. package/test/transfer-replace-merge.test.js +187 -0
  154. package/test/trash-address.test.js +23 -0
  155. package/test/trash-view.test.js +37 -0
  156. package/test/trashbrowse.test.js +135 -0
  157. package/ui/AboutFacts.qml +78 -0
  158. package/ui/ArchiveCards.qml +95 -0
  159. package/ui/ArchiveCompressDialog.qml +378 -0
  160. package/ui/ArchiveHereConfirm.qml +127 -0
  161. package/ui/ArchivePasswordDialog.qml +257 -0
  162. package/ui/Backend.qml +775 -0
  163. package/ui/BulkOldNames.qml +47 -0
  164. package/ui/BulkRenameDialog.qml +380 -0
  165. package/ui/CardFrame.qml +67 -0
  166. package/ui/CardScroll.qml +79 -0
  167. package/ui/CheckBox.qml +73 -0
  168. package/ui/ChromeBar.qml +360 -0
  169. package/ui/ChromeButton.qml +131 -0
  170. package/ui/ChromeModes.qml +43 -0
  171. package/ui/CodeLines.qml +256 -0
  172. package/ui/CodeRefusal.qml +52 -0
  173. package/ui/CollideConfirm.qml +147 -0
  174. package/ui/CollideHost.qml +167 -0
  175. package/ui/ColumnPane.qml +525 -0
  176. package/ui/ColumnRow.qml +380 -0
  177. package/ui/ColumnsArea.qml +594 -0
  178. package/ui/ColumnsLanding.qml +147 -0
  179. package/ui/CompareView.qml +321 -0
  180. package/ui/ContextMenu.qml +743 -0
  181. package/ui/ConvertDialog.qml +456 -0
  182. package/ui/CountedWorker.qml +7 -0
  183. package/ui/Crumb.qml +64 -0
  184. package/ui/CrumbDrop.qml +25 -0
  185. package/ui/CsvTable.qml +394 -0
  186. package/ui/CursorMark.qml +41 -0
  187. package/ui/DefaultClaim.qml +130 -0
  188. package/ui/DeviceLock.qml +47 -0
  189. package/ui/DeviceMounts.qml +540 -0
  190. package/ui/DialogButton.qml +150 -0
  191. package/ui/DialogField.qml +147 -0
  192. package/ui/DialogHeader.qml +31 -0
  193. package/ui/DialogScrim.qml +20 -0
  194. package/ui/DialogTitle.qml +37 -0
  195. package/ui/Divider.qml +9 -0
  196. package/ui/DropInto.qml +126 -0
  197. package/ui/DropTarget.qml +35 -0
  198. package/ui/DropboxMark.qml +60 -0
  199. package/ui/EmptyState.qml +150 -0
  200. package/ui/EscapeHint.qml +11 -0
  201. package/ui/FactsTable.qml +54 -0
  202. package/ui/FastScrollHandler.qml +476 -0
  203. package/ui/FatNamesConfirm.qml +157 -0
  204. package/ui/Favourites.qml +143 -0
  205. package/ui/FigureService.qml +120 -0
  206. package/ui/FileDrag.qml +267 -0
  207. package/ui/FilterStrip.qml +133 -0
  208. package/ui/FitMetrics.qml +22 -0
  209. package/ui/FlashDriveRows.qml +137 -0
  210. package/ui/FlashHost.qml +72 -0
  211. package/ui/FlashImageRow.qml +104 -0
  212. package/ui/FlashRunner.qml +119 -0
  213. package/ui/FlashStepRow.qml +172 -0
  214. package/ui/FlashStrip.qml +38 -0
  215. package/ui/FlashView.qml +397 -0
  216. package/ui/FleaMark.qml +88 -0
  217. package/ui/FlyoutFade.qml +23 -0
  218. package/ui/FontPane.qml +170 -0
  219. package/ui/Glass.qml +114 -0
  220. package/ui/GlassTagger.qml +59 -0
  221. package/ui/Glyph.qml +64 -0
  222. package/ui/GlyphSolid.qml +22 -0
  223. package/ui/GridArea.qml +664 -0
  224. package/ui/GridTile.qml +325 -0
  225. package/ui/GvfsBridge.qml +164 -0
  226. package/ui/Header.qml +433 -0
  227. package/ui/HoverTimers.qml +39 -0
  228. package/ui/HtmlClip.qml +30 -0
  229. package/ui/HtmlPane.qml +63 -0
  230. package/ui/HyprlandMark.qml +45 -0
  231. package/ui/Ipc.qml +1005 -0
  232. package/ui/IpcControls.qml +7 -0
  233. package/ui/IpcMenuState.qml +48 -0
  234. package/ui/IpcPreviewState.qml +185 -0
  235. package/ui/JumpPath.qml +51 -0
  236. package/ui/KeymapSheet.qml +561 -0
  237. package/ui/KeymapSheetResult.qml +89 -0
  238. package/ui/KindStack.qml +40 -0
  239. package/ui/LangMark.qml +51 -0
  240. package/ui/LangMarkLoader.qml +26 -0
  241. package/ui/List.qml +480 -0
  242. package/ui/LoadingState.qml +54 -0
  243. package/ui/LocalSend.qml +56 -0
  244. package/ui/LocalSendMark.qml +73 -0
  245. package/ui/MarkdownBlockView.qml +311 -0
  246. package/ui/MarkdownBlocks.qml +35 -0
  247. package/ui/MarkdownFigure.qml +254 -0
  248. package/ui/MarkdownImages.qml +72 -0
  249. package/ui/MarkdownList.qml +81 -0
  250. package/ui/MarkdownMathsText.qml +97 -0
  251. package/ui/MarkdownPane.qml +83 -0
  252. package/ui/MarkdownPictures.qml +41 -0
  253. package/ui/MarkdownQuote.qml +52 -0
  254. package/ui/MarkdownRemote.qml +82 -0
  255. package/ui/MarkdownSource.qml +155 -0
  256. package/ui/MarkdownTable.qml +222 -0
  257. package/ui/MarkdownTableScroll.qml +64 -0
  258. package/ui/MarkdownTableWheel.qml +126 -0
  259. package/ui/MarkdownText.qml +87 -0
  260. package/ui/MarkdownWorker.js +132 -0
  261. package/ui/MatchText.qml +99 -0
  262. package/ui/MediaSession.qml +38 -0
  263. package/ui/MediaSound.qml +26 -0
  264. package/ui/MediaStrip.qml +191 -0
  265. package/ui/MediaTrack.qml +36 -0
  266. package/ui/MediaVolume.qml +54 -0
  267. package/ui/MenuActionDialog.qml +396 -0
  268. package/ui/MenuEdgeFade.qml +24 -0
  269. package/ui/MenuHost.qml +227 -0
  270. package/ui/MenuRow.qml +351 -0
  271. package/ui/MountListing.qml +100 -0
  272. package/ui/NetworkDialog.qml +435 -0
  273. package/ui/NetworkForm.qml +426 -0
  274. package/ui/NetworkMounts.qml +913 -0
  275. package/ui/NetworkPlaces.qml +127 -0
  276. package/ui/OpenWithDialog.qml +613 -0
  277. package/ui/Opener.qml +95 -0
  278. package/ui/Pane.qml +1320 -0
  279. package/ui/PaneMenuActions.qml +527 -0
  280. package/ui/PanePath.qml +90 -0
  281. package/ui/PaneRail.qml +268 -0
  282. package/ui/PaneStates.qml +88 -0
  283. package/ui/PaneSwap.qml +339 -0
  284. package/ui/PaneWire.qml +601 -0
  285. package/ui/ParkedWait.qml +9 -0
  286. package/ui/PathEntry.qml +186 -0
  287. package/ui/PathJump.qml +400 -0
  288. package/ui/PdfViewer.qml +297 -0
  289. package/ui/PermissionsDialog.qml +658 -0
  290. package/ui/PermissionsHeadings.qml +31 -0
  291. package/ui/PhoneMounts.qml +67 -0
  292. package/ui/PickerAnswers.qml +75 -0
  293. package/ui/PickerBox.qml +26 -0
  294. package/ui/PickerChrome.qml +295 -0
  295. package/ui/PickerFilter.qml +97 -0
  296. package/ui/PickerGrid.qml +308 -0
  297. package/ui/PickerHeader.qml +28 -0
  298. package/ui/PickerLifecycle.qml +27 -0
  299. package/ui/PickerList.qml +218 -0
  300. package/ui/PickerListing.qml +149 -0
  301. package/ui/PickerPathBar.qml +127 -0
  302. package/ui/PickerPlaces.qml +189 -0
  303. package/ui/PickerRecent.qml +92 -0
  304. package/ui/PickerSave.qml +101 -0
  305. package/ui/PickerSelection.qml +155 -0
  306. package/ui/PickerWindow.qml +846 -0
  307. package/ui/PowerSectorsReader.qml +10 -0
  308. package/ui/PrebuildDriver.qml +146 -0
  309. package/ui/Preview.qml +1005 -0
  310. package/ui/PreviewAnimation.qml +24 -0
  311. package/ui/PreviewArchive.qml +91 -0
  312. package/ui/PreviewColumn.qml +553 -0
  313. package/ui/PreviewEdge.qml +63 -0
  314. package/ui/PreviewFacts.qml +30 -0
  315. package/ui/PreviewFactsLine.qml +34 -0
  316. package/ui/PreviewHtml.qml +233 -0
  317. package/ui/PreviewImage.qml +253 -0
  318. package/ui/PreviewImagePan.qml +13 -0
  319. package/ui/PreviewImageSharp.qml +32 -0
  320. package/ui/PreviewLines.qml +106 -0
  321. package/ui/PreviewMarkdown.qml +706 -0
  322. package/ui/PreviewMedia.qml +250 -0
  323. package/ui/PreviewPdf.qml +482 -0
  324. package/ui/PreviewScroll.qml +201 -0
  325. package/ui/PreviewSwap.qml +335 -0
  326. package/ui/PreviewText.qml +149 -0
  327. package/ui/ProtocolChip.qml +18 -0
  328. package/ui/QuickLookArchive.qml +41 -0
  329. package/ui/QuickLookBar.qml +103 -0
  330. package/ui/QuickLookPrepare.qml +355 -0
  331. package/ui/QuickLookSwap.qml +10 -0
  332. package/ui/QuickLookWarm.qml +65 -0
  333. package/ui/RailDrop.qml +155 -0
  334. package/ui/RailHeading.qml +19 -0
  335. package/ui/RailPlaces.qml +38 -0
  336. package/ui/RailTrashRow.qml +67 -0
  337. package/ui/RenameField.qml +353 -0
  338. package/ui/RendererRetry.qml +11 -0
  339. package/ui/ResizeHandle.qml +52 -0
  340. package/ui/Reveal.qml +54 -0
  341. package/ui/Row.qml +476 -0
  342. package/ui/RowDrag.qml +213 -0
  343. package/ui/RowDropTarget.qml +27 -0
  344. package/ui/RunCard.qml +286 -0
  345. package/ui/Scripts.qml +65 -0
  346. package/ui/SearchStrip.qml +232 -0
  347. package/ui/SelectionBand.qml +140 -0
  348. package/ui/SelectionPreview.qml +370 -0
  349. package/ui/SettingsFavourite.qml +122 -0
  350. package/ui/SettingsGroup.qml +96 -0
  351. package/ui/SettingsHint.qml +12 -0
  352. package/ui/SettingsMetrics.qml +29 -0
  353. package/ui/SettingsPane.qml +178 -0
  354. package/ui/SettingsPanel.qml +547 -0
  355. package/ui/SettingsRail.qml +128 -0
  356. package/ui/SettingsRow.qml +409 -0
  357. package/ui/SettingsRuler.qml +85 -0
  358. package/ui/SettingsSegment.qml +85 -0
  359. package/ui/ShareBrowser.qml +113 -0
  360. package/ui/ShareLink.qml +67 -0
  361. package/ui/ShelfPins.qml +101 -0
  362. package/ui/Sidebar.qml +728 -0
  363. package/ui/SidebarRow.qml +358 -0
  364. package/ui/Spinner.qml +60 -0
  365. package/ui/StableModel.qml +89 -0
  366. package/ui/StateMessage.qml +84 -0
  367. package/ui/StatusBar.qml +512 -0
  368. package/ui/StatusFileName.qml +27 -0
  369. package/ui/TabBar.qml +673 -0
  370. package/ui/TabDragGeometry.qml +60 -0
  371. package/ui/TagMenuMark.qml +52 -0
  372. package/ui/TagRailSection.qml +53 -0
  373. package/ui/TagSlot.qml +40 -0
  374. package/ui/TagState.qml +150 -0
  375. package/ui/TagSwatch.qml +28 -0
  376. package/ui/Taildrop.qml +86 -0
  377. package/ui/TailscaleMark.qml +50 -0
  378. package/ui/TerminalService.qml +69 -0
  379. package/ui/TerminalTab.qml +48 -0
  380. package/ui/TerminalTabs.qml +27 -0
  381. package/ui/Theme.qml +460 -0
  382. package/ui/ThemeColors.qml +43 -0
  383. package/ui/TransferCard.qml +239 -0
  384. package/ui/TrashConfirm.qml +129 -0
  385. package/ui/TrashDropHandler.qml +11 -0
  386. package/ui/TrashHost.qml +202 -0
  387. package/ui/TrashMonitor.qml +30 -0
  388. package/ui/TrashToolbar.qml +19 -0
  389. package/ui/TrashView.qml +492 -0
  390. package/ui/UnlockDialog.qml +450 -0
  391. package/ui/UnlockHost.qml +206 -0
  392. package/ui/UpdateCheck.qml +97 -0
  393. package/ui/UserDirs.qml +25 -0
  394. package/ui/ViewState.qml +565 -0
  395. package/ui/ViewportScrollBar.qml +195 -0
  396. package/ui/ViewportScrollBars.qml +25 -0
  397. package/ui/WebPreview.qml +33 -0
  398. package/ui/WebPreviewView.qml +26 -0
  399. package/ui/WindowBody.qml +829 -0
  400. package/ui/WindowDrag.qml +35 -0
  401. package/ui/boot/Commons/AudioNodes.qml +50 -0
  402. package/ui/boot/Commons/AudioNodesModel.js +96 -0
  403. package/ui/boot/Commons/Border.qml +243 -0
  404. package/ui/boot/Commons/BorderGeometry.js +373 -0
  405. package/ui/boot/Commons/Color.qml +258 -0
  406. package/ui/boot/Commons/I18n.qml +118 -0
  407. package/ui/boot/Commons/InputDevices.qml +112 -0
  408. package/ui/boot/Commons/InputMethodState.qml +38 -0
  409. package/ui/boot/Commons/IpcRegistry.qml +77 -0
  410. package/ui/boot/Commons/Numbers.js +19 -0
  411. package/ui/boot/Commons/Plural.js +91 -0
  412. package/ui/boot/Commons/ShellIpc.qml +12 -0
  413. package/ui/boot/Commons/Style.qml +561 -0
  414. package/ui/boot/Commons/Translations.qml +100 -0
  415. package/ui/boot/Commons/UntypedInput.qml +152 -0
  416. package/ui/boot/Commons/Util.qml +188 -0
  417. package/ui/boot/Commons/qmldir +13 -0
  418. package/ui/boot/LICENSE-omarchy +20 -0
  419. package/ui/boot/Ui/BackgroundMedia.qml +49 -0
  420. package/ui/boot/Ui/BarIconButton.qml +106 -0
  421. package/ui/boot/Ui/BarIconContent.qml +38 -0
  422. package/ui/boot/Ui/BarIndicator.qml +53 -0
  423. package/ui/boot/Ui/BarWidget.qml +50 -0
  424. package/ui/boot/Ui/BorderOverlay.qml +54 -0
  425. package/ui/boot/Ui/BorderSurface.qml +40 -0
  426. package/ui/boot/Ui/Button.qml +224 -0
  427. package/ui/boot/Ui/ButtonGroup.qml +131 -0
  428. package/ui/boot/Ui/ConfirmDialog.qml +134 -0
  429. package/ui/boot/Ui/CursorSurface.qml +42 -0
  430. package/ui/boot/Ui/Dropdown.qml +245 -0
  431. package/ui/boot/Ui/FilterInput.qml +26 -0
  432. package/ui/boot/Ui/IconContentBounds.qml +141 -0
  433. package/ui/boot/Ui/KeyboardPanel.qml +453 -0
  434. package/ui/boot/Ui/MultiSelect.qml +624 -0
  435. package/ui/boot/Ui/NumberField.qml +86 -0
  436. package/ui/boot/Ui/OpticalGlyph.qml +68 -0
  437. package/ui/boot/Ui/OverlayWindow.qml +102 -0
  438. package/ui/boot/Ui/Panel.qml +60 -0
  439. package/ui/boot/Ui/PanelActionButton.qml +105 -0
  440. package/ui/boot/Ui/PanelController.qml +16 -0
  441. package/ui/boot/Ui/PanelHero.qml +112 -0
  442. package/ui/boot/Ui/PanelKeyCatcher.qml +100 -0
  443. package/ui/boot/Ui/PanelSectionHeader.qml +31 -0
  444. package/ui/boot/Ui/PanelSeparator.qml +19 -0
  445. package/ui/boot/Ui/PanelSlider.qml +156 -0
  446. package/ui/boot/Ui/PanelToolTip.qml +50 -0
  447. package/ui/boot/Ui/PluginBarApi.qml +89 -0
  448. package/ui/boot/Ui/PointerMoveGate.qml +54 -0
  449. package/ui/boot/Ui/PopupCard.qml +181 -0
  450. package/ui/boot/Ui/ScreenMoveRemap.qml +43 -0
  451. package/ui/boot/Ui/SearchableDropdown.qml +354 -0
  452. package/ui/boot/Ui/SizedImage.qml +125 -0
  453. package/ui/boot/Ui/SpeedTestOverlay.qml +412 -0
  454. package/ui/boot/Ui/TextField.qml +58 -0
  455. package/ui/boot/Ui/Toggle.qml +118 -0
  456. package/ui/boot/Ui/ToggleSwitch.qml +115 -0
  457. package/ui/boot/Ui/WidgetButton.qml +172 -0
  458. package/ui/boot/Ui/qmldir +41 -0
  459. package/ui/boot/fleatab.qml +50 -0
  460. package/ui/boot/picker.qml +39 -0
  461. package/ui/boot/shell.qml +131 -0
  462. package/ui/boot/tabtearoff.qml +51 -0
  463. package/ui/js/Anchor.js +379 -0
  464. package/ui/js/AnchorHold.js +162 -0
  465. package/ui/js/Archive.js +157 -0
  466. package/ui/js/ArchiveCard.js +44 -0
  467. package/ui/js/ArchiveOps.js +44 -0
  468. package/ui/js/BackReturn.js +118 -0
  469. package/ui/js/BulkRename.js +100 -0
  470. package/ui/js/Buttons.js +54 -0
  471. package/ui/js/ChromeKeys.js +116 -0
  472. package/ui/js/ClipMarks.js +73 -0
  473. package/ui/js/ClipSelection.js +67 -0
  474. package/ui/js/Clipboard.js +179 -0
  475. package/ui/js/Cloud.js +97 -0
  476. package/ui/js/CodeRuns.js +72 -0
  477. package/ui/js/Collide.js +212 -0
  478. package/ui/js/ColumnFit.js +28 -0
  479. package/ui/js/ColumnMenu.js +111 -0
  480. package/ui/js/Columns.js +298 -0
  481. package/ui/js/ColumnsCarry.js +103 -0
  482. package/ui/js/Compare.js +74 -0
  483. package/ui/js/Contrast.js +157 -0
  484. package/ui/js/ControlReader.js +42 -0
  485. package/ui/js/Convert.js +52 -0
  486. package/ui/js/CopyAs.js +52 -0
  487. package/ui/js/Crumbs.js +178 -0
  488. package/ui/js/Csv.js +231 -0
  489. package/ui/js/Density.js +44 -0
  490. package/ui/js/Devices.js +440 -0
  491. package/ui/js/DirSizes.js +180 -0
  492. package/ui/js/Drag.js +360 -0
  493. package/ui/js/DragOut.js +166 -0
  494. package/ui/js/DropDev.js +52 -0
  495. package/ui/js/Dropbox.js +41 -0
  496. package/ui/js/Eject.js +217 -0
  497. package/ui/js/Errors.js +188 -0
  498. package/ui/js/ExtThumbs.js +115 -0
  499. package/ui/js/Facts.js +402 -0
  500. package/ui/js/FigureDate.js +14 -0
  501. package/ui/js/Filter.js +285 -0
  502. package/ui/js/Find.js +46 -0
  503. package/ui/js/Flash.js +184 -0
  504. package/ui/js/FlashCard.js +79 -0
  505. package/ui/js/FlashEndings.js +125 -0
  506. package/ui/js/FlashPane.js +116 -0
  507. package/ui/js/FleaBin.js +12 -0
  508. package/ui/js/Focus.js +504 -0
  509. package/ui/js/FolderSorts.js +108 -0
  510. package/ui/js/FolderViews.js +44 -0
  511. package/ui/js/Format.js +314 -0
  512. package/ui/js/Fuzzy.js +141 -0
  513. package/ui/js/GlassTag.js +72 -0
  514. package/ui/js/Grid.js +33 -0
  515. package/ui/js/GridGeometry.js +90 -0
  516. package/ui/js/GridNames.js +153 -0
  517. package/ui/js/GvfsBridge.js +200 -0
  518. package/ui/js/HostClipboard.js +29 -0
  519. package/ui/js/Icons.js +218 -0
  520. package/ui/js/Input.js +50 -0
  521. package/ui/js/Jump.js +200 -0
  522. package/ui/js/KeyName.js +64 -0
  523. package/ui/js/Keymap.js +401 -0
  524. package/ui/js/Kinds.js +164 -0
  525. package/ui/js/LICENSES/ISC-lucide.txt +43 -0
  526. package/ui/js/LangMarkPaths.js +47 -0
  527. package/ui/js/LangMarks.js +120 -0
  528. package/ui/js/Lists.js +11 -0
  529. package/ui/js/LocalSend.js +39 -0
  530. package/ui/js/LockedMenu.js +63 -0
  531. package/ui/js/MakeDefault.js +186 -0
  532. package/ui/js/MarkBox.js +7 -0
  533. package/ui/js/Markdown.js +119 -0
  534. package/ui/js/MarkdownLists.js +86 -0
  535. package/ui/js/MarkdownMaths.js +58 -0
  536. package/ui/js/MarkdownPictures.js +32 -0
  537. package/ui/js/MarkdownPrepared.js +139 -0
  538. package/ui/js/MarkdownTableFit.js +34 -0
  539. package/ui/js/Marks.js +148 -0
  540. package/ui/js/Marquee.js +96 -0
  541. package/ui/js/Match.js +93 -0
  542. package/ui/js/Material.js +109 -0
  543. package/ui/js/MdBlocks.js +437 -0
  544. package/ui/js/MdBreak.js +71 -0
  545. package/ui/js/MdChunks.js +70 -0
  546. package/ui/js/MdContainer.js +137 -0
  547. package/ui/js/MdDocument.js +337 -0
  548. package/ui/js/MdEmph.js +97 -0
  549. package/ui/js/MdEntity.js +108 -0
  550. package/ui/js/MdEntityTable.js +223 -0
  551. package/ui/js/MdEscape.js +59 -0
  552. package/ui/js/MdFront.js +37 -0
  553. package/ui/js/MdHold.js +32 -0
  554. package/ui/js/MdHtml.js +307 -0
  555. package/ui/js/MdHtmlBlock.js +290 -0
  556. package/ui/js/MdHtmlHeading.js +53 -0
  557. package/ui/js/MdHtmlImage.js +179 -0
  558. package/ui/js/MdInline.js +154 -0
  559. package/ui/js/MdItems.js +212 -0
  560. package/ui/js/MdLeaf.js +309 -0
  561. package/ui/js/MdLink.js +196 -0
  562. package/ui/js/MdMath.js +67 -0
  563. package/ui/js/MdParagraphs.js +138 -0
  564. package/ui/js/MdRefs.js +232 -0
  565. package/ui/js/MdResolve.js +226 -0
  566. package/ui/js/MdRun.js +300 -0
  567. package/ui/js/MdUrl.js +226 -0
  568. package/ui/js/Menu.js +514 -0
  569. package/ui/js/MenuContext.js +85 -0
  570. package/ui/js/MenuFit.js +13 -0
  571. package/ui/js/MenuRefresh.js +74 -0
  572. package/ui/js/MenuWheel.js +35 -0
  573. package/ui/js/Messages.js +186 -0
  574. package/ui/js/Motion.js +16 -0
  575. package/ui/js/Mounts.js +320 -0
  576. package/ui/js/MouseNav.js +13 -0
  577. package/ui/js/Nav.js +329 -0
  578. package/ui/js/NetFs.js +26 -0
  579. package/ui/js/OpenWith.js +83 -0
  580. package/ui/js/Ops.js +585 -0
  581. package/ui/js/Palette.js +33 -0
  582. package/ui/js/PathBar.js +260 -0
  583. package/ui/js/Permissions.js +179 -0
  584. package/ui/js/Phones.js +112 -0
  585. package/ui/js/Picker.js +353 -0
  586. package/ui/js/PlaceMenu.js +96 -0
  587. package/ui/js/Places.js +265 -0
  588. package/ui/js/PreviewAsk.js +21 -0
  589. package/ui/js/PreviewKeys.js +155 -0
  590. package/ui/js/PreviewSettle.js +29 -0
  591. package/ui/js/PreviewSwap.js +101 -0
  592. package/ui/js/PropertyFacts.js +144 -0
  593. package/ui/js/Protocols.js +296 -0
  594. package/ui/js/QuickLookKinds.js +27 -0
  595. package/ui/js/QuickLookRect.js +24 -0
  596. package/ui/js/RailDrop.js +51 -0
  597. package/ui/js/RailKeys.js +87 -0
  598. package/ui/js/RailMenu.js +133 -0
  599. package/ui/js/Recent.js +135 -0
  600. package/ui/js/RecentMode.js +156 -0
  601. package/ui/js/Reload.js +60 -0
  602. package/ui/js/Renderer.js +9 -0
  603. package/ui/js/RunFile.js +143 -0
  604. package/ui/js/Scripts.js +28 -0
  605. package/ui/js/Scroll.js +304 -0
  606. package/ui/js/ScrollOff.js +69 -0
  607. package/ui/js/Search.js +478 -0
  608. package/ui/js/Selection.js +97 -0
  609. package/ui/js/Settings.js +476 -0
  610. package/ui/js/SettingsAbout.js +97 -0
  611. package/ui/js/SettingsShelf.js +52 -0
  612. package/ui/js/SheetKeys.js +42 -0
  613. package/ui/js/SheetQuery.js +281 -0
  614. package/ui/js/ShelfPile.js +27 -0
  615. package/ui/js/SlowClick.js +53 -0
  616. package/ui/js/SlowOp.js +6 -0
  617. package/ui/js/Sort.js +134 -0
  618. package/ui/js/Startup.js +63 -0
  619. package/ui/js/StateWords.js +17 -0
  620. package/ui/js/Status.js +238 -0
  621. package/ui/js/Swap.js +166 -0
  622. package/ui/js/TabMove.js +39 -0
  623. package/ui/js/Tabs.js +751 -0
  624. package/ui/js/Tags.js +134 -0
  625. package/ui/js/Taildrop.js +128 -0
  626. package/ui/js/Tap.js +180 -0
  627. package/ui/js/TextSize.js +107 -0
  628. package/ui/js/Thumbs.js +158 -0
  629. package/ui/js/Transfer.js +172 -0
  630. package/ui/js/Trash.js +84 -0
  631. package/ui/js/TrashDates.js +47 -0
  632. package/ui/js/TrashDrop.js +64 -0
  633. package/ui/js/UiState.js +438 -0
  634. package/ui/js/Unlock.js +152 -0
  635. package/ui/js/Update.js +130 -0
  636. package/ui/js/UserDirs.js +56 -0
  637. package/ui/qmldir +230 -0
@@ -0,0 +1,613 @@
1
+ import QtQuick
2
+ import qs.Commons
3
+ import "." as Flea
4
+ import "js/OpenWith.js" as OpenWith
5
+ import "js/Format.js" as Format
6
+ import "js/Input.js" as Input
7
+
8
+ // OpenWith.html rule 4: the Convert popup family, and the one place a default handler is written.
9
+ // The flyout beside it overrides once and writes nothing; only this card touches mimeapps.list.
10
+ Item {
11
+ id: root
12
+
13
+ property bool opened: false
14
+ readonly property string action: "openWith"
15
+ property int requestId: 0
16
+ property Item focusHolder: null
17
+ property bool busy: false
18
+ property bool committing: false
19
+ property string errorText: ""
20
+ property string path: ""
21
+ property string kind: ""
22
+ property string mime: ""
23
+ property var handlers: []
24
+ property var installed: []
25
+ property bool always: false
26
+ property int cursor: 0
27
+ // 0 search, 1 list, 2 always box, 3 Cancel, 4 Open: rule 8's own cycle, and it wraps; the cursor row draws on 0 and 1 only, as Enter from either opens it.
28
+ property int focusPart: 0
29
+ // Where a row or the ground last saw the pointer, -1 since opening, so a row built or scrolled under a resting pointer never takes the cursor.
30
+ property point pointerGlobal: Qt.point(-1, -1)
31
+
32
+ signal requested(var message)
33
+ signal closed()
34
+
35
+ readonly property string name: root.path.split("/").pop()
36
+ readonly property var rows: OpenWith.rows(root.handlers, root.installed, root.kind, field.text)
37
+ readonly property var applications: OpenWith.applications(root.rows)
38
+ readonly property var chosen: root.applications[root.cursor]
39
+ readonly property bool canSubmit: !root.busy && root.chosen !== undefined
40
+ // The shared menu-dialog probe reads these; ui/Ipc.qml openWithState adds this board's own rows.
41
+ readonly property var facts: ({})
42
+ readonly property bool deletionActive: false
43
+ readonly property var confirmationItem: null
44
+ readonly property var cardItem: card
45
+ readonly property var closeItem: cancelButton
46
+ readonly property var submitItem: openButton
47
+ readonly property var fieldItem: field
48
+ readonly property var titleRuleItem: title.ruleItem
49
+ readonly property var searchItem: searchBox
50
+ readonly property var applicationsItem: list
51
+ readonly property var alwaysItem: alwaysBox
52
+ function applicationItem(index) { return list.itemAtIndex(OpenWith.rowOf(root.rows, index)) }
53
+
54
+ // Rule 5: seven applications before the list scrolls. Measured once from the whole catalogue, so
55
+ // rule 6's "keeps its height" holds for every search the user types into it, not only the empty one.
56
+ readonly property int viewportRows: 7
57
+ readonly property int eyebrowHeight: Math.round(Theme.font.caption * 1.6) + Theme.spacing.gap
58
+ property int listHeight: root.viewportRows * Theme.rowHeight
59
+ readonly property int clampMargin: 8
60
+ // DialogButtons040 at size 14: the field is 18 px under the title rule (two gaps) and 31 px over the eyebrow's ink (the row's own 15 plus 16).
61
+ readonly property int searchLead: 2 * Theme.spacing.gap
62
+ readonly property real eyebrowLeadBoard: 16
63
+ readonly property real bodySmallBoard: 13
64
+ readonly property int searchTrail: Math.round(root.eyebrowLeadBoard * Theme.font.bodySmall / root.bodySmallBoard)
65
+
66
+ anchors.fill: parent
67
+ visible: root.opened || root.opacity > 0
68
+ // Closed means no input, even while the fade-out is still drawn.
69
+ enabled: root.opened
70
+ opacity: 0
71
+ z: 2
72
+ Flea.Reveal { target: root; shown: root.opened; lift: card }
73
+
74
+ // The shared signature the Loader calls both cards with; this one reads the item off the reply.
75
+ function open(operation, id, sourceFolder, holder) {
76
+ root.requestId = id
77
+ root.focusHolder = holder
78
+ root.path = ""
79
+ root.kind = ""
80
+ root.mime = ""
81
+ root.handlers = []
82
+ root.installed = []
83
+ root.always = false
84
+ root.cursor = 0
85
+ root.pointerGlobal = Qt.point(-1, -1)
86
+ root.listHeight = root.viewportRows * Theme.rowHeight
87
+ root.errorText = ""
88
+ root.committing = false
89
+ root.busy = true
90
+ root.focusPart = 0
91
+ field.text = ""
92
+ root.opened = true
93
+ list.contentY = 0
94
+ wheel.resetSteps()
95
+ field.forceActiveFocus()
96
+ // installed: the whole catalogue, which only this card draws. The flyout asks without it,
97
+ // so a right-click does not pay for a walk of every applications directory on the box.
98
+ root.requested({c: "menuaction", op: "applications", id: id, installed: true})
99
+ }
100
+
101
+ function close() {
102
+ if (!root.opened) return
103
+ // The close op expires the snapshot and cancels the owned launcher, so Cancel during a launch
104
+ // ends the child rather than leaving it running behind a card that is already gone.
105
+ root.requested({c: "menuaction", op: "close", id: root.requestId})
106
+ root.opened = false
107
+ root.settleClosed()
108
+ root.closed()
109
+ if (root.focusHolder) root.focusHolder.forceActiveFocus()
110
+ }
111
+
112
+ // A closed card keeps its busy look while it fades out; the reset waits until it is gone.
113
+ function settleClosed() {
114
+ if (root.opened || root.opacity !== 0) return
115
+ root.busy = false
116
+ root.committing = false
117
+ }
118
+ onOpacityChanged: root.settleClosed()
119
+
120
+ // The pane calls this when the folder is refreshed under an open dialog. Nothing to redraw here:
121
+ // the backend rechecks the captured item on submit, so a selection that moved refuses there.
122
+ function sourceChanged() {}
123
+
124
+ function receive(message) {
125
+ if (!root.opened || message.id !== root.requestId) return
126
+ if (message.op === "applications") {
127
+ root.busy = false
128
+ if (!message.ok) { root.errorText = message.error || "The list of applications could not be read."; return }
129
+ root.path = message.path || ""
130
+ root.kind = message.kind || ""
131
+ root.mime = message.mime || ""
132
+ root.handlers = message.applications || []
133
+ root.installed = message.installed || []
134
+ root.cursor = 0
135
+ root.listHeight = OpenWith.viewportHeight(root.rows, root.viewportRows, Theme.rowHeight, root.eyebrowHeight)
136
+ return
137
+ }
138
+ if (message.op !== "openWith") return
139
+ if (message.ok) { root.close(); return }
140
+ root.busy = false
141
+ root.committing = false
142
+ if (!message.cancelled) root.errorText = message.error || "The application could not be opened."
143
+ }
144
+
145
+ function commit() {
146
+ if (!root.canSubmit) return
147
+ root.errorText = ""
148
+ root.busy = true
149
+ root.committing = true
150
+ root.requested({c: "menuaction", op: "openWith", id: root.requestId,
151
+ application: root.chosen.id, always: root.always})
152
+ }
153
+
154
+ function moveCursor(delta) {
155
+ var count = root.applications.length
156
+ if (!count) return
157
+ root.focusPart = 1
158
+ root.cursor = Math.max(0, Math.min(count - 1, root.cursor + delta))
159
+ list.forceActiveFocus()
160
+ // By index, not by item: a ListView has no item for a row it has not realized yet.
161
+ list.positionViewAtIndex(OpenWith.rowOf(root.rows, root.cursor), ListView.Contain)
162
+ }
163
+
164
+ // Wheel step: cursor and view move, focus never does; a busy list answers nothing.
165
+ function stepCursor(delta) {
166
+ if (root.busy) return
167
+ var count = root.applications.length
168
+ if (!count) return
169
+ root.cursor = Math.max(0, Math.min(count - 1, root.cursor + delta))
170
+ list.positionViewAtIndex(OpenWith.rowOf(root.rows, root.cursor), ListView.Contain)
171
+ }
172
+
173
+ function stepFocus(back) {
174
+ if (root.busy) return
175
+ var parts = [0, 1, 2, 3, 4]
176
+ var at = parts.indexOf(root.focusPart)
177
+ root.focusPart = parts[(at + (back ? parts.length - 1 : 1)) % parts.length]
178
+ var item = [field, list, alwaysBox, cancelButton, openButton][root.focusPart]
179
+ item.forceActiveFocus()
180
+ }
181
+
182
+ // Rule 8: typing anywhere goes to the search, so a key nothing else claimed lands in the field.
183
+ function typeIntoSearch(text) {
184
+ root.focusPart = 0
185
+ field.forceActiveFocus()
186
+ field.insert(field.length, text)
187
+ }
188
+
189
+ Rectangle {
190
+ anchors.fill: parent
191
+ color: Theme.color.background
192
+ opacity: 0.5
193
+
194
+ MouseArea {
195
+ id: ground
196
+ anchors.fill: parent
197
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
198
+ hoverEnabled: true
199
+ onEntered: root.pointerGlobal = ground.mapToItem(null, ground.mouseX, ground.mouseY)
200
+ onPositionChanged: function (mouse) { root.pointerGlobal = ground.mapToItem(null, mouse.x, mouse.y) }
201
+ onClicked: root.close()
202
+ onWheel: function (wheel) { wheel.accepted = true }
203
+ }
204
+ }
205
+
206
+ Rectangle {
207
+ id: card
208
+ x: Theme.cardOrigin(root.width, width)
209
+ y: Theme.cardOrigin(root.height, height)
210
+ width: Theme.cardSpan(Theme.space(480) * Theme.dialogWidthRatio, root.width - 2 * root.clampMargin)
211
+ // Clamped to the window; the body scrolls whatever the clamp cut, so a short screen cannot
212
+ // put Cancel and Open past the bottom edge with no way to reach them.
213
+ height: Theme.cardSpan(body.wanted + 2 * Theme.spacing.rowPaddingX, root.height - 2 * root.clampMargin)
214
+ color: Theme.color.surface
215
+ border.width: Theme.spacing.hairline
216
+ border.color: Theme.color.mutedFrame
217
+ radius: Style.cornerRadius
218
+
219
+ // The checkbox handler takes a passive grab, so without this sink its press reaches the ground.
220
+ MouseArea {
221
+ id: cardSink
222
+ anchors.fill: parent
223
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
224
+ hoverEnabled: true
225
+ onEntered: root.pointerGlobal = cardSink.mapToItem(null, cardSink.mouseX, cardSink.mouseY)
226
+ onPositionChanged: function (mouse) { root.pointerGlobal = cardSink.mapToItem(null, mouse.x, mouse.y) }
227
+ onClicked: {}
228
+ onWheel: function (wheel) { wheel.accepted = true }
229
+ }
230
+
231
+ Flea.CardFrame {
232
+ id: body
233
+ bleedY: Theme.focusClearance
234
+ anchors.fill: parent
235
+ anchors.topMargin: Theme.spacing.rowPaddingX - Theme.focusClearance
236
+ anchors.bottomMargin: Theme.spacing.rowPaddingX - Theme.focusClearance
237
+ spacing: 0
238
+
239
+ // RunCard's own header: the esc hint at the right and the rule inset to the content edge.
240
+ title: Flea.DialogHeader {
241
+ id: title
242
+ x: Theme.spacing.rowPaddingX
243
+ width: parent.width - 2 * Theme.spacing.rowPaddingX
244
+ elide: Text.ElideMiddle
245
+ // The registry names the item, so the title says only what it knows until it lands.
246
+ text: root.name.length > 0 ? Format.fill(OpenWith.WORDS.titleNamed, root.name) : "Open with"
247
+ }
248
+
249
+ Column {
250
+ width: parent.width
251
+
252
+ // Rule 4: the Network board's field, with the lens beside it and a clear mark once it holds text.
253
+ Item {
254
+ width: parent.width
255
+ height: root.searchLead + searchBox.height + root.searchTrail
256
+
257
+ Rectangle {
258
+ id: searchBox
259
+ anchors.left: parent.left
260
+ anchors.right: parent.right
261
+ anchors.leftMargin: Theme.spacing.rowPaddingX
262
+ anchors.rightMargin: Theme.spacing.rowPaddingX
263
+ anchors.bottom: parent.bottom
264
+ anchors.bottomMargin: root.searchTrail
265
+ height: Theme.rowHeight - Theme.spacing.rowPaddingY
266
+ color: Theme.color.background
267
+ border.width: Theme.spacing.hairline
268
+ border.color: field.activeFocus ? Theme.color.accent : Theme.color.mutedFrame
269
+
270
+ Flea.Glyph {
271
+ id: lens
272
+ anchors.left: parent.left
273
+ anchors.leftMargin: Theme.spacing.gap
274
+ anchors.verticalCenter: parent.verticalCenter
275
+ width: Theme.font.body
276
+ height: Theme.font.body
277
+ name: "search"
278
+ color: Theme.color.mutedFrame
279
+ }
280
+
281
+ TextInput {
282
+ id: field
283
+ anchors.left: lens.right
284
+ anchors.right: clear.left
285
+ anchors.leftMargin: Theme.spacing.gap
286
+ anchors.rightMargin: Theme.spacing.gap
287
+ anchors.verticalCenter: parent.verticalCenter
288
+ color: Theme.color.foreground
289
+ selectionColor: Theme.color.accent
290
+ selectedTextColor: Theme.color.background
291
+ font.family: Theme.font.family
292
+ font.pixelSize: Theme.font.body
293
+ clip: true
294
+ activeFocusOnTab: false
295
+ Keys.forwardTo: [keys]
296
+ onTextChanged: { root.cursor = 0; list.contentY = 0 }
297
+ }
298
+
299
+ Text {
300
+ anchors.left: field.left
301
+ anchors.verticalCenter: parent.verticalCenter
302
+ visible: field.text.length === 0
303
+ text: "Search applications"
304
+ color: Theme.color.muted
305
+ font.family: Theme.font.family
306
+ font.pixelSize: Theme.font.body
307
+ textFormat: Text.PlainText
308
+ elide: Text.ElideRight
309
+ }
310
+
311
+ Item {
312
+ id: clear
313
+ anchors.right: parent.right
314
+ anchors.rightMargin: Theme.spacing.gap
315
+ anchors.verticalCenter: parent.verticalCenter
316
+ width: field.text.length > 0 ? Theme.font.caption : 0
317
+ height: Theme.font.caption
318
+
319
+ Flea.Glyph {
320
+ anchors.fill: parent
321
+ visible: field.text.length > 0
322
+ name: "x"
323
+ color: Theme.color.mutedFrame
324
+ }
325
+
326
+ TapHandler {
327
+ enabled: field.text.length > 0
328
+ acceptedButtons: Qt.LeftButton
329
+ gesturePolicy: TapHandler.ReleaseWithinBounds
330
+ onTapped: { field.text = ""; root.focusPart = 0; field.forceActiveFocus() }
331
+ }
332
+ }
333
+ }
334
+ }
335
+
336
+ Item {
337
+ width: parent.width
338
+ height: root.listHeight
339
+
340
+ // A ListView, not a Repeater: a box holds well over a hundred applications and the
341
+ // model is a fresh array on every keystroke, so a Repeater rebuilt every delegate,
342
+ // each one a MenuRow with its own Shape, for every character typed.
343
+ ListView {
344
+ id: list
345
+ anchors.fill: parent
346
+ clip: true
347
+ model: root.rows
348
+ reuseItems: true
349
+ boundsBehavior: Flickable.StopAtBounds
350
+ activeFocusOnTab: false
351
+ Keys.forwardTo: [keys]
352
+ Flea.FastScrollHandler {
353
+ id: wheel
354
+ parent: list
355
+ flickable: list
356
+ // The app list steps the highlight like a menu: one row a notch, one
357
+ // row per row height of gained touchpad travel. No bar, no lane.
358
+ stepMode: true
359
+ stepRowHeight: Theme.rowHeight
360
+ stepBy: function (delta) { root.stepCursor(delta) }
361
+ }
362
+
363
+ delegate: Item {
364
+ id: row
365
+ required property var modelData
366
+ required property int index
367
+ readonly property bool isEyebrow: row.modelData.eyebrow !== undefined
368
+ // The cursor counts applications only, so an eyebrow never takes it.
369
+ readonly property int appIndex: row.isEyebrow ? -1 : row.modelData.at
370
+ width: list.width
371
+ height: row.isEyebrow ? root.eyebrowHeight : menuRow.height
372
+
373
+ Rectangle {
374
+ anchors.top: parent.top
375
+ width: parent.width
376
+ height: Theme.spacing.hairline
377
+ visible: row.isEyebrow && row.modelData.rule === true
378
+ color: Theme.color.mutedFrame
379
+ opacity: 0.4
380
+ }
381
+
382
+ Text {
383
+ id: eyebrow
384
+ visible: row.isEyebrow
385
+ anchors.left: parent.left
386
+ anchors.leftMargin: Theme.spacing.rowPaddingX
387
+ anchors.bottom: parent.bottom
388
+ text: row.isEyebrow ? row.modelData.eyebrow : ""
389
+ color: Theme.color.muted
390
+ font.family: Theme.font.family
391
+ font.pixelSize: Theme.font.caption
392
+ font.bold: true
393
+ font.capitalization: Font.AllUppercase
394
+ font.letterSpacing: Theme.font.caption * 0.14
395
+ textFormat: Text.PlainText
396
+ }
397
+
398
+ Flea.MenuRow {
399
+ id: menuRow
400
+ visible: !row.isEyebrow
401
+ width: parent.width
402
+ entry: row.isEyebrow ? ({}) : ({ label: row.modelData.label, action: "",
403
+ icon: row.modelData.icon, glyph: "app-window",
404
+ hint: row.modelData.default === true ? "default" : "" })
405
+ current: !row.isEyebrow && root.focusPart < 2 && root.cursor === row.appIndex
406
+ lastPointerGlobal: root.pointerGlobal
407
+ onPointerSeen: function (at) { root.pointerGlobal = at }
408
+ // The cursor follows the pointer, the focus does not: a pointer crossing
409
+ // this list on its way to Cancel used to make Enter open a row instead.
410
+ onPointerMoved: if (!row.isEyebrow) root.cursor = row.appIndex
411
+ onActivated: if (!row.isEyebrow) { root.focusPart = 1; root.cursor = row.appIndex; root.commit() }
412
+ }
413
+ }
414
+ }
415
+
416
+ // Rule 6: the area keeps its height and centres the one caption that says why it is empty.
417
+ Text {
418
+ anchors.centerIn: parent
419
+ width: parent.width - 4 * Theme.spacing.rowPaddingX
420
+ visible: !root.busy && !root.rows.length && field.text.trim().length > 0
421
+ text: OpenWith.noMatch(field.text)
422
+ color: Theme.color.muted
423
+ font.family: Theme.font.family
424
+ font.pixelSize: Theme.font.caption
425
+ textFormat: Text.PlainText
426
+ horizontalAlignment: Text.AlignHCenter
427
+ wrapMode: Text.Wrap
428
+ }
429
+
430
+ // The fade that says the viewport cut the list, drawn in the card's own ground inside its frame.
431
+ Rectangle {
432
+ anchors.left: parent.left
433
+ anchors.right: parent.right
434
+ anchors.leftMargin: Theme.spacing.hairline
435
+ anchors.rightMargin: Theme.spacing.hairline
436
+ anchors.bottom: parent.bottom
437
+ height: Theme.spacing.gap
438
+ visible: list.contentHeight > list.height && list.contentY < list.contentHeight - list.height - 1
439
+ gradient: Gradient {
440
+ GradientStop { position: 0; color: Qt.rgba(Theme.color.surface.r, Theme.color.surface.g, Theme.color.surface.b, 0) }
441
+ GradientStop { position: 1; color: Theme.color.surface }
442
+ }
443
+ }
444
+ }
445
+
446
+ // The Always checkbox row; a tap or Space toggles it.
447
+ Item {
448
+ id: alwaysBox
449
+ width: parent.width
450
+ height: Theme.rowHeight
451
+ activeFocusOnTab: true
452
+ Keys.forwardTo: [keys]
453
+ Accessible.role: Accessible.CheckBox
454
+ Accessible.name: alwaysLabel.text
455
+ Accessible.checkable: true
456
+ Accessible.checked: root.always
457
+ Accessible.onPressAction: root.always = !root.always
458
+
459
+ Rectangle {
460
+ anchors.top: parent.top
461
+ width: parent.width
462
+ height: Theme.spacing.hairline
463
+ color: Theme.color.mutedFrame
464
+ opacity: 0.4
465
+ }
466
+
467
+ Item {
468
+ id: box
469
+ anchors.left: parent.left
470
+ anchors.leftMargin: Theme.spacing.rowPaddingX
471
+ anchors.verticalCenter: parent.verticalCenter
472
+ width: ruleBox.implicitWidth
473
+ height: ruleBox.implicitHeight
474
+
475
+ Flea.CheckBox {
476
+ id: ruleBox
477
+ value: root.always ? "on" : "off"
478
+ focused: root.focusPart === 2
479
+ }
480
+ }
481
+
482
+ Text {
483
+ id: alwaysLabel
484
+ anchors.left: box.right
485
+ anchors.leftMargin: Theme.spacing.gap
486
+ anchors.right: parent.right
487
+ anchors.rightMargin: Theme.spacing.rowPaddingX
488
+ anchors.verticalCenter: parent.verticalCenter
489
+ text: root.kind.length > 0 ? Format.fill(OpenWith.WORDS.alwaysKind, root.kind)
490
+ : "Always use this application for this file type"
491
+ color: Theme.color.foreground
492
+ font.family: Theme.font.family
493
+ font.pixelSize: Theme.font.body
494
+ textFormat: Text.PlainText
495
+ wrapMode: Text.Wrap
496
+ }
497
+
498
+ TapHandler {
499
+ acceptedButtons: Qt.LeftButton
500
+ gesturePolicy: TapHandler.ReleaseWithinBounds
501
+ onTapped: { root.focusPart = 2; root.always = !root.always; alwaysBox.forceActiveFocus() }
502
+ }
503
+ }
504
+
505
+ Text {
506
+ id: consequence
507
+ width: parent.width
508
+ leftPadding: Theme.spacing.rowPaddingX + box.width + Theme.spacing.gap
509
+ rightPadding: Theme.spacing.rowPaddingX
510
+ bottomPadding: Theme.spacing.gap
511
+ // The board's one line: the box above already says what is written.
512
+ text: "Undo does not reverse this; change it here again."
513
+ color: Theme.color.muted
514
+ font.family: Theme.font.family
515
+ font.pixelSize: Theme.font.caption
516
+ textFormat: Text.PlainText
517
+ wrapMode: Text.Wrap
518
+ }
519
+
520
+ // The status slot is always laid out, two caption lines tall (the network slot's rowHeight) inside its padding, so rest, busy and a short error keep one card height; only a longer error grows it.
521
+ Text {
522
+ width: parent.width
523
+ leftPadding: Theme.spacing.rowPaddingX
524
+ rightPadding: Theme.spacing.rowPaddingX
525
+ bottomPadding: Theme.spacing.gap
526
+ height: Math.max(Theme.rowHeight + topPadding + bottomPadding, implicitHeight)
527
+ text: root.committing ? "Opening…" : root.errorText
528
+ color: root.committing ? Theme.color.muted : Theme.color.errorOnSurface
529
+ font.family: Theme.font.family
530
+ font.pixelSize: Theme.font.caption
531
+ textFormat: Text.PlainText
532
+ wrapMode: Text.Wrap
533
+ }
534
+ }
535
+
536
+ buttons: Item {
537
+ width: parent.width
538
+ height: Math.max(cancelButton.implicitHeight, openButton.implicitHeight)
539
+
540
+ Row {
541
+ anchors.right: parent.right
542
+ anchors.rightMargin: Theme.spacing.rowPaddingX
543
+ spacing: Theme.spacing.gap
544
+
545
+ Flea.DialogButton {
546
+ id: cancelButton
547
+ label: "Cancel"
548
+ focused: root.focusPart === 3
549
+ activeFocusOnTab: true
550
+ Keys.forwardTo: [keys]
551
+ onActivated: root.close()
552
+ }
553
+
554
+ Flea.DialogButton {
555
+ id: openButton
556
+ label: "Open"
557
+ primary: true
558
+ focused: root.focusPart === 4
559
+ available: root.canSubmit
560
+ activeFocusOnTab: true
561
+ Keys.forwardTo: [keys]
562
+ onActivated: root.commit()
563
+ }
564
+ }
565
+ }
566
+ }
567
+ }
568
+
569
+ Item {
570
+ id: keys
571
+ anchors.fill: parent
572
+
573
+ // Rule 8's whole map. A printable key nobody above claimed is search text, whatever holds focus.
574
+ Keys.onPressed: function (event) {
575
+ event.accepted = true
576
+ if (event.key === Qt.Key_Escape) { root.close(); return }
577
+ if (event.key === Qt.Key_Tab || event.key === Qt.Key_Backtab) {
578
+ root.stepFocus(event.key === Qt.Key_Backtab || (event.modifiers & Qt.ShiftModifier) !== 0)
579
+ return
580
+ }
581
+ if (root.busy) return
582
+ // j and k move only while the search line is both empty and unfocused: from the field
583
+ // they are the first letters of kate, krita and joplin, and stealing them lost the query.
584
+ var quiet = field.text.length === 0 && root.focusPart !== 0
585
+ if (event.key === Qt.Key_Down || (quiet && event.key === Qt.Key_J)) { root.moveCursor(1); return }
586
+ if (event.key === Qt.Key_Up || (quiet && event.key === Qt.Key_K)) { root.moveCursor(-1); return }
587
+ if (event.key === Qt.Key_PageDown) { root.moveCursor(root.viewportRows); return }
588
+ if (event.key === Qt.Key_PageUp) { root.moveCursor(-root.viewportRows); return }
589
+ // Backspace edits the search from anywhere, the mirror of typing reaching it from anywhere.
590
+ if (event.key === Qt.Key_Backspace && !field.activeFocus) {
591
+ if (field.text.length > 0) { root.focusPart = 0; field.forceActiveFocus(); field.remove(field.length - 1, field.length) }
592
+ return
593
+ }
594
+ if (event.key === Qt.Key_Space) {
595
+ // Space answers the control that holds focus; only from the list, the box itself or an
596
+ // empty search line is it rule 7's toggle rather than a character.
597
+ if (root.focusPart === 3) { root.close(); return }
598
+ if (root.focusPart === 4) { root.commit(); return }
599
+ if (root.focusPart !== 0 || field.text.length === 0) { root.always = !root.always; return }
600
+ }
601
+ if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
602
+ if (root.focusPart === 3) root.close()
603
+ else if (root.focusPart === 2) root.always = !root.always
604
+ else root.commit()
605
+ return
606
+ }
607
+ if (Input.isPrintable(event.text.charAt(0)) && !(event.modifiers & Qt.ControlModifier)) {
608
+ if (!field.activeFocus) { root.typeIntoSearch(event.text); return }
609
+ }
610
+ event.accepted = false
611
+ }
612
+ }
613
+ }