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.
- package/LICENSE +22 -0
- package/README.md +478 -2
- package/THIRD-PARTY-NOTICES.md +29 -0
- package/demos/App.java +5 -0
- package/demos/Dockerfile +4 -0
- package/demos/Main.kt +3 -0
- package/demos/Program.cs +1 -0
- package/demos/README.md +12 -0
- package/demos/app.dart +3 -0
- package/demos/app.deb +0 -0
- package/demos/app.js +1 -0
- package/demos/backup.tar +0 -0
- package/demos/budget.xlsx +0 -0
- package/demos/build.sh +2 -0
- package/demos/bundle.zip +0 -0
- package/demos/clip.mp4 +0 -0
- package/demos/data.sqlite +0 -0
- package/demos/disk.iso +0 -0
- package/demos/engine.cpp +5 -0
- package/demos/firmware.bin +0 -0
- package/demos/flake.nix +4 -0
- package/demos/folder/inside.txt +1 -0
- package/demos/font.ttf +0 -0
- package/demos/index.html +5 -0
- package/demos/index.php +2 -0
- package/demos/init.lua +1 -0
- package/demos/letter.docx +0 -0
- package/demos/lib.rs +3 -0
- package/demos/main.c +6 -0
- package/demos/main.h +3 -0
- package/demos/math-and-diagrams.md +200 -0
- package/demos/notes.tar.gz +0 -0
- package/demos/notes.txt +3 -0
- package/demos/photo.png +0 -0
- package/demos/program +2 -0
- package/demos/report.pdf +32 -0
- package/demos/script.py +1 -0
- package/demos/server.go +7 -0
- package/demos/settings.json +4 -0
- package/demos/slides.pptx +0 -0
- package/demos/song.mp3 +0 -0
- package/demos/style.css +4 -0
- package/demos/tool.rb +1 -0
- package/demos/types.ts +2 -0
- package/docs/pele.md +23 -0
- package/docs/protocol.md +3420 -0
- package/docs/temml.md +63 -0
- package/index.js +107 -0
- package/package.json +34 -4
- package/src/archive.js +402 -0
- package/src/archiveops.js +697 -0
- package/src/backend.js +369 -0
- package/src/bulkrename.js +95 -0
- package/src/clip-host.js +76 -0
- package/src/clip.js +462 -0
- package/src/code.js +168 -0
- package/src/compare.js +74 -0
- package/src/create.js +128 -0
- package/src/dirsize.js +147 -0
- package/src/figure-svg.js +530 -0
- package/src/figure-thread.js +23 -0
- package/src/figure.js +132 -0
- package/src/find.js +55 -0
- package/src/flea.js +39 -0
- package/src/fsinfo.js +39 -0
- package/src/highlight.js +141 -0
- package/src/html.js +52 -0
- package/src/kinds.js +89 -0
- package/src/listing.js +130 -0
- package/src/markdown-html.js +317 -0
- package/src/mathml.js +186 -0
- package/src/menu.js +180 -0
- package/src/meta.js +129 -0
- package/src/office.js +810 -0
- package/src/order.js +100 -0
- package/src/peek.js +49 -0
- package/src/pele-wrapper.js +695 -0
- package/src/permissions.js +180 -0
- package/src/places.js +313 -0
- package/src/preview-language.js +10 -0
- package/src/transfer.js +669 -0
- package/src/trash-record.js +41 -0
- package/src/trash.js +210 -0
- package/src/trashbrowse.js +326 -0
- package/src/uistate.js +393 -0
- package/src/uistore.js +168 -0
- package/src/vendor/LICENSES/Apache-2.0.txt +202 -0
- package/src/vendor/LICENSES/MIT-katex-2015.txt +27 -0
- package/src/vendor/LICENSES/MIT-katex.txt +21 -0
- package/src/vendor/LICENSES/MIT-mermaid.txt +21 -0
- package/src/vendor/LICENSES/MIT-pele.txt +40 -0
- package/src/vendor/LICENSES/MIT-perseus.txt +18 -0
- package/src/vendor/LICENSES/MIT-temml.txt +21 -0
- package/src/vendor/pele.js +145 -0
- package/src/vendor/temml.mjs +14708 -0
- package/src/watch.js +98 -0
- package/src/wayland/client.js +109 -0
- package/src/wayland/protocol.js +55 -0
- package/src/wayland/protocols/ext-data-control-v1.xml +276 -0
- package/src/wayland/protocols/wayland.xml +3248 -0
- package/src/wayland/protocols/wlr-data-control-unstable-v1.xml +278 -0
- package/src/wayland/resource-io.js +6 -0
- package/src/wayland/socket-discovery.js +26 -0
- package/src/wayland/transport-posix.js +120 -0
- package/src/wayland/transport-win32.js +11 -0
- package/src/wayland/transport.js +3 -0
- package/src/wayland/win32-resources.js +80 -0
- package/src/wayland/win32-wire.js +62 -0
- package/test/archive.test.js +80 -0
- package/test/bench-markdown-scroll.mjs +190 -0
- package/test/clip-host.test.js +113 -0
- package/test/code-preview.test.js +35 -0
- package/test/compare-ui-paths.test.js +24 -0
- package/test/compare.test.js +54 -0
- package/test/delete-trash.test.js +67 -0
- package/test/dirsize.test.js +138 -0
- package/test/file-ops.test.js +241 -0
- package/test/find-contents.test.js +161 -0
- package/test/find-input.test.js +66 -0
- package/test/fixtures/pele-parity.json +1006 -0
- package/test/highlight-launcher.test.js +35 -0
- package/test/html-preview.test.js +22 -0
- package/test/input.test.js +15 -0
- package/test/keymap.test.js +26 -0
- package/test/language-icons.test.js +36 -0
- package/test/launcher.test.js +51 -0
- package/test/manual-code-scroll.mjs +28 -0
- package/test/manual-column-scroll.mjs +24 -0
- package/test/manual-compare-ui.mjs +20 -0
- package/test/manual-find-status.mjs +37 -0
- package/test/manual-html-security.mjs +23 -0
- package/test/manual-html-ui.mjs +30 -0
- package/test/manual-syntax-preview.mjs +26 -0
- package/test/manual-trash-ui.mjs +86 -0
- package/test/markdown-diagrams.test.js +93 -0
- package/test/markdown-html.test.js +105 -0
- package/test/mathml.test.js +92 -0
- package/test/menu-transfer.test.js +57 -0
- package/test/office-preview.test.js +154 -0
- package/test/pele-parity.test.js +28 -0
- package/test/places.test.js +134 -0
- package/test/preview-keys.test.js +60 -0
- package/test/preview-language.test.js +22 -0
- package/test/status-filename.test.js +20 -0
- package/test/transfer-replace-merge.test.js +187 -0
- package/test/trash-address.test.js +23 -0
- package/test/trash-view.test.js +37 -0
- package/test/trashbrowse.test.js +135 -0
- package/ui/AboutFacts.qml +78 -0
- package/ui/ArchiveCards.qml +68 -0
- package/ui/ArchiveCompressDialog.qml +378 -0
- package/ui/ArchivePasswordDialog.qml +257 -0
- package/ui/Backend.qml +771 -0
- package/ui/BulkOldNames.qml +47 -0
- package/ui/BulkRenameDialog.qml +380 -0
- package/ui/CardFrame.qml +67 -0
- package/ui/CardScroll.qml +79 -0
- package/ui/CheckBox.qml +73 -0
- package/ui/ChromeBar.qml +360 -0
- package/ui/ChromeButton.qml +131 -0
- package/ui/ChromeModes.qml +43 -0
- package/ui/CodeLines.qml +256 -0
- package/ui/CodeRefusal.qml +52 -0
- package/ui/CollideConfirm.qml +147 -0
- package/ui/CollideHost.qml +167 -0
- package/ui/ColumnPane.qml +523 -0
- package/ui/ColumnRow.qml +380 -0
- package/ui/ColumnsArea.qml +594 -0
- package/ui/ColumnsLanding.qml +147 -0
- package/ui/CompareView.qml +321 -0
- package/ui/ContextMenu.qml +743 -0
- package/ui/ConvertDialog.qml +456 -0
- package/ui/CountedWorker.qml +7 -0
- package/ui/Crumb.qml +64 -0
- package/ui/CrumbDrop.qml +25 -0
- package/ui/CsvTable.qml +394 -0
- package/ui/CursorMark.qml +41 -0
- package/ui/DefaultClaim.qml +130 -0
- package/ui/DeviceLock.qml +47 -0
- package/ui/DeviceMounts.qml +540 -0
- package/ui/DialogButton.qml +150 -0
- package/ui/DialogField.qml +147 -0
- package/ui/DialogHeader.qml +31 -0
- package/ui/DialogScrim.qml +20 -0
- package/ui/DialogTitle.qml +37 -0
- package/ui/Divider.qml +9 -0
- package/ui/DropInto.qml +126 -0
- package/ui/DropTarget.qml +35 -0
- package/ui/DropboxMark.qml +60 -0
- package/ui/EmptyState.qml +150 -0
- package/ui/EscapeHint.qml +11 -0
- package/ui/FactsTable.qml +54 -0
- package/ui/FastScrollHandler.qml +476 -0
- package/ui/FatNamesConfirm.qml +157 -0
- package/ui/Favourites.qml +143 -0
- package/ui/FigureService.qml +120 -0
- package/ui/FileDrag.qml +267 -0
- package/ui/FilterStrip.qml +133 -0
- package/ui/FitMetrics.qml +22 -0
- package/ui/FlashDriveRows.qml +137 -0
- package/ui/FlashHost.qml +72 -0
- package/ui/FlashImageRow.qml +104 -0
- package/ui/FlashRunner.qml +119 -0
- package/ui/FlashStepRow.qml +172 -0
- package/ui/FlashStrip.qml +38 -0
- package/ui/FlashView.qml +397 -0
- package/ui/FleaMark.qml +88 -0
- package/ui/FlyoutFade.qml +23 -0
- package/ui/FontPane.qml +170 -0
- package/ui/Glass.qml +114 -0
- package/ui/GlassTagger.qml +59 -0
- package/ui/Glyph.qml +64 -0
- package/ui/GlyphSolid.qml +22 -0
- package/ui/GridArea.qml +664 -0
- package/ui/GridTile.qml +325 -0
- package/ui/GvfsBridge.qml +164 -0
- package/ui/Header.qml +433 -0
- package/ui/HoverTimers.qml +39 -0
- package/ui/HtmlClip.qml +30 -0
- package/ui/HtmlPane.qml +63 -0
- package/ui/HyprlandMark.qml +45 -0
- package/ui/Ipc.qml +1005 -0
- package/ui/IpcControls.qml +7 -0
- package/ui/IpcMenuState.qml +48 -0
- package/ui/IpcPreviewState.qml +185 -0
- package/ui/JumpPath.qml +51 -0
- package/ui/KeymapSheet.qml +561 -0
- package/ui/KeymapSheetResult.qml +89 -0
- package/ui/KindStack.qml +40 -0
- package/ui/LangMark.qml +51 -0
- package/ui/LangMarkLoader.qml +26 -0
- package/ui/List.qml +480 -0
- package/ui/LoadingState.qml +54 -0
- package/ui/LocalSend.qml +56 -0
- package/ui/LocalSendMark.qml +73 -0
- package/ui/MarkdownBlockView.qml +311 -0
- package/ui/MarkdownBlocks.qml +35 -0
- package/ui/MarkdownFigure.qml +254 -0
- package/ui/MarkdownImages.qml +72 -0
- package/ui/MarkdownList.qml +81 -0
- package/ui/MarkdownMathsText.qml +97 -0
- package/ui/MarkdownPane.qml +83 -0
- package/ui/MarkdownPictures.qml +41 -0
- package/ui/MarkdownQuote.qml +52 -0
- package/ui/MarkdownRemote.qml +82 -0
- package/ui/MarkdownSource.qml +155 -0
- package/ui/MarkdownTable.qml +222 -0
- package/ui/MarkdownTableScroll.qml +64 -0
- package/ui/MarkdownTableWheel.qml +126 -0
- package/ui/MarkdownText.qml +87 -0
- package/ui/MarkdownWorker.js +132 -0
- package/ui/MatchText.qml +99 -0
- package/ui/MediaSession.qml +38 -0
- package/ui/MediaSound.qml +26 -0
- package/ui/MediaStrip.qml +191 -0
- package/ui/MediaTrack.qml +36 -0
- package/ui/MediaVolume.qml +54 -0
- package/ui/MenuActionDialog.qml +396 -0
- package/ui/MenuEdgeFade.qml +24 -0
- package/ui/MenuHost.qml +227 -0
- package/ui/MenuRow.qml +351 -0
- package/ui/MountListing.qml +100 -0
- package/ui/NetworkDialog.qml +435 -0
- package/ui/NetworkForm.qml +426 -0
- package/ui/NetworkMounts.qml +913 -0
- package/ui/NetworkPlaces.qml +127 -0
- package/ui/OpenWithDialog.qml +613 -0
- package/ui/Opener.qml +115 -0
- package/ui/Pane.qml +1296 -0
- package/ui/PaneMenuActions.qml +527 -0
- package/ui/PanePath.qml +90 -0
- package/ui/PaneRail.qml +239 -0
- package/ui/PaneStates.qml +88 -0
- package/ui/PaneSwap.qml +339 -0
- package/ui/PaneWire.qml +605 -0
- package/ui/ParkedWait.qml +9 -0
- package/ui/PathEntry.qml +186 -0
- package/ui/PathJump.qml +400 -0
- package/ui/PdfViewer.qml +297 -0
- package/ui/PermissionsDialog.qml +658 -0
- package/ui/PermissionsHeadings.qml +31 -0
- package/ui/PhoneMounts.qml +67 -0
- package/ui/PickerAnswers.qml +75 -0
- package/ui/PickerBox.qml +26 -0
- package/ui/PickerChrome.qml +295 -0
- package/ui/PickerFilter.qml +97 -0
- package/ui/PickerGrid.qml +308 -0
- package/ui/PickerHeader.qml +28 -0
- package/ui/PickerLifecycle.qml +27 -0
- package/ui/PickerList.qml +218 -0
- package/ui/PickerListing.qml +149 -0
- package/ui/PickerPathBar.qml +127 -0
- package/ui/PickerPlaces.qml +189 -0
- package/ui/PickerRecent.qml +92 -0
- package/ui/PickerSave.qml +101 -0
- package/ui/PickerSelection.qml +155 -0
- package/ui/PickerWindow.qml +846 -0
- package/ui/PowerSectorsReader.qml +10 -0
- package/ui/PrebuildDriver.qml +146 -0
- package/ui/Preview.qml +1004 -0
- package/ui/PreviewAnimation.qml +24 -0
- package/ui/PreviewArchive.qml +66 -0
- package/ui/PreviewColumn.qml +551 -0
- package/ui/PreviewEdge.qml +63 -0
- package/ui/PreviewFacts.qml +30 -0
- package/ui/PreviewFactsLine.qml +34 -0
- package/ui/PreviewHtml.qml +233 -0
- package/ui/PreviewImage.qml +253 -0
- package/ui/PreviewImagePan.qml +13 -0
- package/ui/PreviewImageSharp.qml +32 -0
- package/ui/PreviewLines.qml +106 -0
- package/ui/PreviewMarkdown.qml +706 -0
- package/ui/PreviewMedia.qml +250 -0
- package/ui/PreviewPdf.qml +482 -0
- package/ui/PreviewScroll.qml +201 -0
- package/ui/PreviewSwap.qml +335 -0
- package/ui/PreviewText.qml +149 -0
- package/ui/ProtocolChip.qml +18 -0
- package/ui/QuickLookArchive.qml +38 -0
- package/ui/QuickLookBar.qml +103 -0
- package/ui/QuickLookPrepare.qml +355 -0
- package/ui/QuickLookSwap.qml +10 -0
- package/ui/QuickLookWarm.qml +65 -0
- package/ui/RailDrop.qml +155 -0
- package/ui/RailHeading.qml +19 -0
- package/ui/RailPlaces.qml +38 -0
- package/ui/RailTrashRow.qml +67 -0
- package/ui/RenameField.qml +353 -0
- package/ui/RendererRetry.qml +11 -0
- package/ui/ResizeHandle.qml +52 -0
- package/ui/Reveal.qml +54 -0
- package/ui/Row.qml +476 -0
- package/ui/RowDrag.qml +213 -0
- package/ui/RowDropTarget.qml +27 -0
- package/ui/RunCard.qml +286 -0
- package/ui/Scripts.qml +65 -0
- package/ui/SearchStrip.qml +232 -0
- package/ui/SelectionBand.qml +140 -0
- package/ui/SelectionPreview.qml +370 -0
- package/ui/SettingsFavourite.qml +122 -0
- package/ui/SettingsGroup.qml +96 -0
- package/ui/SettingsHint.qml +12 -0
- package/ui/SettingsMetrics.qml +29 -0
- package/ui/SettingsPane.qml +178 -0
- package/ui/SettingsPanel.qml +547 -0
- package/ui/SettingsRail.qml +128 -0
- package/ui/SettingsRow.qml +409 -0
- package/ui/SettingsRuler.qml +85 -0
- package/ui/SettingsSegment.qml +85 -0
- package/ui/ShareBrowser.qml +113 -0
- package/ui/ShareLink.qml +67 -0
- package/ui/ShelfPins.qml +101 -0
- package/ui/Sidebar.qml +732 -0
- package/ui/SidebarRow.qml +358 -0
- package/ui/Spinner.qml +60 -0
- package/ui/StableModel.qml +89 -0
- package/ui/StateMessage.qml +84 -0
- package/ui/StatusBar.qml +512 -0
- package/ui/StatusFileName.qml +27 -0
- package/ui/TabBar.qml +673 -0
- package/ui/TabDragGeometry.qml +60 -0
- package/ui/TagMenuMark.qml +52 -0
- package/ui/TagRailSection.qml +53 -0
- package/ui/TagSlot.qml +40 -0
- package/ui/TagState.qml +150 -0
- package/ui/TagSwatch.qml +28 -0
- package/ui/Taildrop.qml +86 -0
- package/ui/TailscaleMark.qml +50 -0
- package/ui/Theme.qml +460 -0
- package/ui/ThemeColors.qml +43 -0
- package/ui/TransferCard.qml +239 -0
- package/ui/TrashConfirm.qml +129 -0
- package/ui/TrashDropHandler.qml +11 -0
- package/ui/TrashHost.qml +202 -0
- package/ui/TrashMonitor.qml +30 -0
- package/ui/TrashToolbar.qml +19 -0
- package/ui/TrashView.qml +492 -0
- package/ui/UnlockDialog.qml +450 -0
- package/ui/UnlockHost.qml +206 -0
- package/ui/UpdateCheck.qml +97 -0
- package/ui/UserDirs.qml +25 -0
- package/ui/ViewState.qml +565 -0
- package/ui/ViewportScrollBar.qml +195 -0
- package/ui/ViewportScrollBars.qml +25 -0
- package/ui/WebPreview.qml +33 -0
- package/ui/WebPreviewView.qml +26 -0
- package/ui/WindowBody.qml +827 -0
- package/ui/WindowDrag.qml +35 -0
- package/ui/boot/Commons/AudioNodes.qml +50 -0
- package/ui/boot/Commons/AudioNodesModel.js +96 -0
- package/ui/boot/Commons/Border.qml +243 -0
- package/ui/boot/Commons/BorderGeometry.js +373 -0
- package/ui/boot/Commons/Color.qml +258 -0
- package/ui/boot/Commons/I18n.qml +118 -0
- package/ui/boot/Commons/InputDevices.qml +112 -0
- package/ui/boot/Commons/InputMethodState.qml +38 -0
- package/ui/boot/Commons/IpcRegistry.qml +77 -0
- package/ui/boot/Commons/Numbers.js +19 -0
- package/ui/boot/Commons/Plural.js +91 -0
- package/ui/boot/Commons/ShellIpc.qml +12 -0
- package/ui/boot/Commons/Style.qml +561 -0
- package/ui/boot/Commons/Translations.qml +100 -0
- package/ui/boot/Commons/UntypedInput.qml +152 -0
- package/ui/boot/Commons/Util.qml +188 -0
- package/ui/boot/Commons/qmldir +13 -0
- package/ui/boot/LICENSE-omarchy +20 -0
- package/ui/boot/Ui/BackgroundMedia.qml +49 -0
- package/ui/boot/Ui/BarIconButton.qml +106 -0
- package/ui/boot/Ui/BarIconContent.qml +38 -0
- package/ui/boot/Ui/BarIndicator.qml +53 -0
- package/ui/boot/Ui/BarWidget.qml +50 -0
- package/ui/boot/Ui/BorderOverlay.qml +54 -0
- package/ui/boot/Ui/BorderSurface.qml +40 -0
- package/ui/boot/Ui/Button.qml +224 -0
- package/ui/boot/Ui/ButtonGroup.qml +131 -0
- package/ui/boot/Ui/ConfirmDialog.qml +134 -0
- package/ui/boot/Ui/CursorSurface.qml +42 -0
- package/ui/boot/Ui/Dropdown.qml +245 -0
- package/ui/boot/Ui/FilterInput.qml +26 -0
- package/ui/boot/Ui/IconContentBounds.qml +141 -0
- package/ui/boot/Ui/KeyboardPanel.qml +453 -0
- package/ui/boot/Ui/MultiSelect.qml +624 -0
- package/ui/boot/Ui/NumberField.qml +86 -0
- package/ui/boot/Ui/OpticalGlyph.qml +68 -0
- package/ui/boot/Ui/OverlayWindow.qml +102 -0
- package/ui/boot/Ui/Panel.qml +60 -0
- package/ui/boot/Ui/PanelActionButton.qml +105 -0
- package/ui/boot/Ui/PanelController.qml +16 -0
- package/ui/boot/Ui/PanelHero.qml +112 -0
- package/ui/boot/Ui/PanelKeyCatcher.qml +100 -0
- package/ui/boot/Ui/PanelSectionHeader.qml +31 -0
- package/ui/boot/Ui/PanelSeparator.qml +19 -0
- package/ui/boot/Ui/PanelSlider.qml +156 -0
- package/ui/boot/Ui/PanelToolTip.qml +50 -0
- package/ui/boot/Ui/PluginBarApi.qml +89 -0
- package/ui/boot/Ui/PointerMoveGate.qml +54 -0
- package/ui/boot/Ui/PopupCard.qml +181 -0
- package/ui/boot/Ui/ScreenMoveRemap.qml +43 -0
- package/ui/boot/Ui/SearchableDropdown.qml +354 -0
- package/ui/boot/Ui/SizedImage.qml +125 -0
- package/ui/boot/Ui/SpeedTestOverlay.qml +412 -0
- package/ui/boot/Ui/TextField.qml +58 -0
- package/ui/boot/Ui/Toggle.qml +118 -0
- package/ui/boot/Ui/ToggleSwitch.qml +115 -0
- package/ui/boot/Ui/WidgetButton.qml +172 -0
- package/ui/boot/Ui/qmldir +41 -0
- package/ui/boot/fleatab.qml +50 -0
- package/ui/boot/picker.qml +39 -0
- package/ui/boot/shell.qml +122 -0
- package/ui/boot/tabtearoff.qml +51 -0
- package/ui/js/Anchor.js +379 -0
- package/ui/js/AnchorHold.js +162 -0
- package/ui/js/Archive.js +157 -0
- package/ui/js/ArchiveCard.js +44 -0
- package/ui/js/ArchiveOps.js +44 -0
- package/ui/js/BackReturn.js +118 -0
- package/ui/js/BulkRename.js +100 -0
- package/ui/js/Buttons.js +54 -0
- package/ui/js/ChromeKeys.js +116 -0
- package/ui/js/ClipMarks.js +73 -0
- package/ui/js/ClipSelection.js +67 -0
- package/ui/js/Clipboard.js +179 -0
- package/ui/js/Cloud.js +97 -0
- package/ui/js/CodeRuns.js +72 -0
- package/ui/js/Collide.js +212 -0
- package/ui/js/ColumnFit.js +28 -0
- package/ui/js/ColumnMenu.js +111 -0
- package/ui/js/Columns.js +298 -0
- package/ui/js/ColumnsCarry.js +103 -0
- package/ui/js/Compare.js +74 -0
- package/ui/js/Contrast.js +157 -0
- package/ui/js/ControlReader.js +42 -0
- package/ui/js/Convert.js +52 -0
- package/ui/js/CopyAs.js +52 -0
- package/ui/js/Crumbs.js +178 -0
- package/ui/js/Csv.js +231 -0
- package/ui/js/Density.js +44 -0
- package/ui/js/Devices.js +440 -0
- package/ui/js/DirSizes.js +180 -0
- package/ui/js/Drag.js +364 -0
- package/ui/js/DragOut.js +166 -0
- package/ui/js/DropDev.js +52 -0
- package/ui/js/Dropbox.js +41 -0
- package/ui/js/Eject.js +217 -0
- package/ui/js/Errors.js +188 -0
- package/ui/js/ExtThumbs.js +115 -0
- package/ui/js/Facts.js +402 -0
- package/ui/js/FigureDate.js +14 -0
- package/ui/js/Filter.js +285 -0
- package/ui/js/Find.js +46 -0
- package/ui/js/Flash.js +184 -0
- package/ui/js/FlashCard.js +79 -0
- package/ui/js/FlashEndings.js +125 -0
- package/ui/js/FlashPane.js +116 -0
- package/ui/js/FleaBin.js +12 -0
- package/ui/js/Focus.js +502 -0
- package/ui/js/FolderSorts.js +108 -0
- package/ui/js/FolderViews.js +44 -0
- package/ui/js/Format.js +305 -0
- package/ui/js/Fuzzy.js +141 -0
- package/ui/js/GlassTag.js +72 -0
- package/ui/js/Grid.js +33 -0
- package/ui/js/GridGeometry.js +90 -0
- package/ui/js/GridNames.js +153 -0
- package/ui/js/GvfsBridge.js +200 -0
- package/ui/js/HostClipboard.js +29 -0
- package/ui/js/Icons.js +218 -0
- package/ui/js/Input.js +50 -0
- package/ui/js/Jump.js +200 -0
- package/ui/js/KeyName.js +64 -0
- package/ui/js/Keymap.js +401 -0
- package/ui/js/Kinds.js +164 -0
- package/ui/js/LICENSES/ISC-lucide.txt +43 -0
- package/ui/js/LangMarkPaths.js +47 -0
- package/ui/js/LangMarks.js +120 -0
- package/ui/js/Lists.js +11 -0
- package/ui/js/LocalSend.js +39 -0
- package/ui/js/LockedMenu.js +63 -0
- package/ui/js/MakeDefault.js +186 -0
- package/ui/js/MarkBox.js +7 -0
- package/ui/js/Markdown.js +119 -0
- package/ui/js/MarkdownLists.js +86 -0
- package/ui/js/MarkdownMaths.js +58 -0
- package/ui/js/MarkdownPictures.js +32 -0
- package/ui/js/MarkdownPrepared.js +139 -0
- package/ui/js/MarkdownTableFit.js +34 -0
- package/ui/js/Marks.js +148 -0
- package/ui/js/Marquee.js +96 -0
- package/ui/js/Match.js +93 -0
- package/ui/js/Material.js +109 -0
- package/ui/js/MdBlocks.js +437 -0
- package/ui/js/MdBreak.js +71 -0
- package/ui/js/MdChunks.js +70 -0
- package/ui/js/MdContainer.js +137 -0
- package/ui/js/MdDocument.js +337 -0
- package/ui/js/MdEmph.js +97 -0
- package/ui/js/MdEntity.js +108 -0
- package/ui/js/MdEntityTable.js +223 -0
- package/ui/js/MdEscape.js +59 -0
- package/ui/js/MdFront.js +37 -0
- package/ui/js/MdHold.js +32 -0
- package/ui/js/MdHtml.js +307 -0
- package/ui/js/MdHtmlBlock.js +290 -0
- package/ui/js/MdHtmlHeading.js +53 -0
- package/ui/js/MdHtmlImage.js +179 -0
- package/ui/js/MdInline.js +154 -0
- package/ui/js/MdItems.js +212 -0
- package/ui/js/MdLeaf.js +309 -0
- package/ui/js/MdLink.js +196 -0
- package/ui/js/MdMath.js +67 -0
- package/ui/js/MdParagraphs.js +138 -0
- package/ui/js/MdRefs.js +232 -0
- package/ui/js/MdResolve.js +226 -0
- package/ui/js/MdRun.js +300 -0
- package/ui/js/MdUrl.js +226 -0
- package/ui/js/Menu.js +514 -0
- package/ui/js/MenuContext.js +85 -0
- package/ui/js/MenuFit.js +13 -0
- package/ui/js/MenuRefresh.js +74 -0
- package/ui/js/MenuWheel.js +35 -0
- package/ui/js/Messages.js +186 -0
- package/ui/js/Motion.js +16 -0
- package/ui/js/Mounts.js +320 -0
- package/ui/js/MouseNav.js +13 -0
- package/ui/js/Nav.js +329 -0
- package/ui/js/NetFs.js +26 -0
- package/ui/js/OpenWith.js +83 -0
- package/ui/js/Ops.js +585 -0
- package/ui/js/Palette.js +33 -0
- package/ui/js/PathBar.js +260 -0
- package/ui/js/Permissions.js +179 -0
- package/ui/js/Phones.js +112 -0
- package/ui/js/Picker.js +353 -0
- package/ui/js/PlaceMenu.js +96 -0
- package/ui/js/Places.js +265 -0
- package/ui/js/PreviewAsk.js +21 -0
- package/ui/js/PreviewKeys.js +155 -0
- package/ui/js/PreviewSettle.js +29 -0
- package/ui/js/PreviewSwap.js +101 -0
- package/ui/js/PropertyFacts.js +144 -0
- package/ui/js/Protocols.js +296 -0
- package/ui/js/QuickLookKinds.js +27 -0
- package/ui/js/QuickLookRect.js +24 -0
- package/ui/js/RailDrop.js +51 -0
- package/ui/js/RailKeys.js +87 -0
- package/ui/js/RailMenu.js +133 -0
- package/ui/js/Recent.js +135 -0
- package/ui/js/RecentMode.js +156 -0
- package/ui/js/Reload.js +60 -0
- package/ui/js/Renderer.js +9 -0
- package/ui/js/RunFile.js +143 -0
- package/ui/js/Scripts.js +28 -0
- package/ui/js/Scroll.js +304 -0
- package/ui/js/ScrollOff.js +69 -0
- package/ui/js/Search.js +478 -0
- package/ui/js/Selection.js +97 -0
- package/ui/js/Settings.js +476 -0
- package/ui/js/SettingsAbout.js +97 -0
- package/ui/js/SettingsShelf.js +52 -0
- package/ui/js/SheetKeys.js +42 -0
- package/ui/js/SheetQuery.js +281 -0
- package/ui/js/ShelfPile.js +27 -0
- package/ui/js/SlowClick.js +53 -0
- package/ui/js/SlowOp.js +6 -0
- package/ui/js/Sort.js +134 -0
- package/ui/js/Startup.js +63 -0
- package/ui/js/StateWords.js +17 -0
- package/ui/js/Status.js +238 -0
- package/ui/js/Swap.js +166 -0
- package/ui/js/TabMove.js +39 -0
- package/ui/js/Tabs.js +736 -0
- package/ui/js/Tags.js +134 -0
- package/ui/js/Taildrop.js +128 -0
- package/ui/js/Tap.js +174 -0
- package/ui/js/TextSize.js +107 -0
- package/ui/js/Thumbs.js +158 -0
- package/ui/js/Transfer.js +172 -0
- package/ui/js/Trash.js +81 -0
- package/ui/js/TrashDates.js +47 -0
- package/ui/js/TrashDrop.js +64 -0
- package/ui/js/UiState.js +438 -0
- package/ui/js/Unlock.js +152 -0
- package/ui/js/Update.js +130 -0
- package/ui/js/UserDirs.js +56 -0
- package/ui/qmldir +228 -0
package/ui/CodeLines.qml
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import QtQuick
|
|
2
|
+
import qs.Commons
|
|
3
|
+
import "js/CodeRuns.js" as CodeRuns
|
|
4
|
+
|
|
5
|
+
// The lines of one file or text, coloured by the backend's code engine, asked a screen-and-margin at a time; a network file's `text` is the caller's.
|
|
6
|
+
Item {
|
|
7
|
+
id: root
|
|
8
|
+
|
|
9
|
+
property var backend: null
|
|
10
|
+
// The backend's name for this view's job; a newer ask on it ends the older one.
|
|
11
|
+
property string slot: "column"
|
|
12
|
+
property string path: ""
|
|
13
|
+
// true sends the bytes in `text` (null until the caller has read them) instead of the path.
|
|
14
|
+
property bool fromText: false
|
|
15
|
+
property var text: null
|
|
16
|
+
property bool active: false
|
|
17
|
+
property bool numbered: false
|
|
18
|
+
property bool wrap: false
|
|
19
|
+
// Enables wheel and drag scrolling in the line viewport.
|
|
20
|
+
property bool scrolls: false
|
|
21
|
+
// Grow from measured delegates only; never scan the entire file to size a lane.
|
|
22
|
+
property real widestLine: 0
|
|
23
|
+
function measureLine(width) {
|
|
24
|
+
if (!root.wrap && isFinite(width) && width > root.widestLine) root.widestLine = width
|
|
25
|
+
}
|
|
26
|
+
readonly property alias viewport: view
|
|
27
|
+
// A Component the list draws above its first line and scrolls with the rows; null for none.
|
|
28
|
+
property Component header: null
|
|
29
|
+
property real pixelSize: Theme.font.caption
|
|
30
|
+
// The most lines drawn, 0 for every line of the file.
|
|
31
|
+
property int limit: 0
|
|
32
|
+
// Screens asked past the view on each side.
|
|
33
|
+
property int margin: 1
|
|
34
|
+
readonly property int lineCap: 400 // The most lines one ask names (docs/protocol.md "code"); a longer window is asked in parts.
|
|
35
|
+
|
|
36
|
+
// A backend that cannot ask (a bare stub) leaves the caller's own text to be drawn plain.
|
|
37
|
+
readonly property bool engine: root.backend !== null && typeof root.backend.askCode === "function"
|
|
38
|
+
// "" until the lines in view are answered, then styled, plain, binary, large or failed.
|
|
39
|
+
property string answer: ""
|
|
40
|
+
property int total: 0
|
|
41
|
+
// The lines held, by 1-based number, read through rowAt; stamp counts changes to it.
|
|
42
|
+
property var held: ({})
|
|
43
|
+
property int stamp: 0
|
|
44
|
+
// The token of the ask in flight, 0 when none: an answer for any other token is dropped.
|
|
45
|
+
property int token: 0
|
|
46
|
+
property bool retiring: false
|
|
47
|
+
// The window of that ask, so the same window is not asked for twice while it is in flight.
|
|
48
|
+
property var asking: null
|
|
49
|
+
readonly property bool settled: root.answer === "styled" || root.answer === "plain"
|
|
50
|
+
readonly property int shown: root.limit > 0 ? Math.min(root.total, root.limit) : root.total
|
|
51
|
+
// True when the lines in view are all held.
|
|
52
|
+
readonly property bool firstScreen: root.settled && root.covered(root.needed().from, root.needed().to)
|
|
53
|
+
// The plain text of the lines drawn, for the readers that check what is on screen.
|
|
54
|
+
readonly property var lines: {
|
|
55
|
+
var out = []
|
|
56
|
+
for (var i = 1; i <= root.shown; i++)
|
|
57
|
+
out.push(root.rowAt(i) ? CodeRuns.plain(root.rowAt(i)) : "")
|
|
58
|
+
return out
|
|
59
|
+
}
|
|
60
|
+
// Indexed by the code reply's role: the foreground, then red, green, yellow, blue, magenta and cyan.
|
|
61
|
+
readonly property var inks: CodeRuns.inks(Theme.palette, Theme.fallbackColor, String(Theme.color.foreground))
|
|
62
|
+
readonly property real rowHeight: metrics.height
|
|
63
|
+
// The gutter is as wide as the widest number it can show, so the text never shifts as it scrolls.
|
|
64
|
+
readonly property real gutterWidth: (Math.max(2, String(root.shown).length) + 1) * metrics.advanceWidth
|
|
65
|
+
|
|
66
|
+
// The runs of line n, undefined until the backend has answered for it; reading it through the stamp makes a binding follow every answer.
|
|
67
|
+
function rowAt(n) {
|
|
68
|
+
return root.stamp >= 0 ? root.held[n] : undefined
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function reset() {
|
|
72
|
+
root.widestLine = 0
|
|
73
|
+
view.contentX = 0
|
|
74
|
+
view.contentY = 0
|
|
75
|
+
root.held = {}
|
|
76
|
+
root.stamp += 1
|
|
77
|
+
root.total = 0
|
|
78
|
+
root.answer = ""
|
|
79
|
+
root.token = 0
|
|
80
|
+
root.asking = null
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Starts a view of a new file or text; the first ask waits for the end of the turn so one change of several properties asks once.
|
|
84
|
+
function fresh() {
|
|
85
|
+
root.reset()
|
|
86
|
+
if (!root.active) {
|
|
87
|
+
askTimer.stop()
|
|
88
|
+
return
|
|
89
|
+
}
|
|
90
|
+
if (!root.engine && root.fromText && root.text !== null)
|
|
91
|
+
root.answerPlain()
|
|
92
|
+
else
|
|
93
|
+
root.schedule()
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// The owned timer coalesces asks and is destroyed with the reader, including a pending ask during a preview handoff.
|
|
97
|
+
function schedule() {
|
|
98
|
+
if (root.active)
|
|
99
|
+
askTimer.restart()
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Sample input: "a\nb\n" holds only lines 1 and 2, as [0, "a"] and [0, "b"], matching the engine's terminal-newline rule.
|
|
103
|
+
function answerPlain() {
|
|
104
|
+
var rows = root.text.length > 0 ? root.text.split("\n") : []
|
|
105
|
+
if (rows.length > 0 && root.text.endsWith("\n"))
|
|
106
|
+
rows.pop()
|
|
107
|
+
var held = {}
|
|
108
|
+
for (var i = 0; i < rows.length && (root.limit <= 0 || i < root.limit); i++)
|
|
109
|
+
held[i + 1] = [0, rows[i].endsWith("\r") ? rows[i].slice(0, -1) : rows[i]]
|
|
110
|
+
root.held = held
|
|
111
|
+
root.stamp += 1
|
|
112
|
+
root.total = rows.length
|
|
113
|
+
root.answer = "plain"
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// The lines the view needs held: those in it plus the margin, never past the file or the limit.
|
|
117
|
+
function needed() {
|
|
118
|
+
var rows = Math.max(1, Math.ceil(view.height / Math.max(1, root.rowHeight)))
|
|
119
|
+
var top = view.contentHeight > 0 ? Math.max(0, view.indexAt(0, view.contentY + 1)) + 1 : 1
|
|
120
|
+
var to = top + rows * (1 + root.margin) - 1
|
|
121
|
+
if (root.limit > 0)
|
|
122
|
+
to = Math.min(to, root.limit)
|
|
123
|
+
if (root.settled)
|
|
124
|
+
to = Math.min(to, root.total)
|
|
125
|
+
return { from: Math.max(1, top - rows * root.margin), to: to }
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function covered(from, to) {
|
|
129
|
+
for (var i = from; i <= to; i++)
|
|
130
|
+
if (!root.rowAt(i))
|
|
131
|
+
return false
|
|
132
|
+
return true
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function ask() {
|
|
136
|
+
if (root.retiring || !root.active || !root.engine || view.height <= 0)
|
|
137
|
+
return
|
|
138
|
+
if (root.answer === "binary" || root.answer === "large" || root.answer === "failed")
|
|
139
|
+
return
|
|
140
|
+
if (root.fromText && root.text === null)
|
|
141
|
+
return
|
|
142
|
+
if (root.fromText && root.text.length === 0) {
|
|
143
|
+
root.answerPlain()
|
|
144
|
+
return
|
|
145
|
+
}
|
|
146
|
+
if (!root.fromText && root.path.length === 0)
|
|
147
|
+
return
|
|
148
|
+
var want = root.needed()
|
|
149
|
+
if (want.to < want.from || (root.settled && root.covered(want.from, want.to)))
|
|
150
|
+
return
|
|
151
|
+
if (root.token !== 0 && root.asking.from === want.from && root.asking.to === want.to)
|
|
152
|
+
return
|
|
153
|
+
root.asking = want
|
|
154
|
+
var from = want.from
|
|
155
|
+
while (from < want.to && root.rowAt(from)) from++
|
|
156
|
+
var source = root.fromText ? { text: root.text, name: root.path.split("/").pop(), lang: "" } : { path: root.path }
|
|
157
|
+
root.token = root.backend.askCode(root.slot, source, from, Math.min(root.lineCap, want.to - from + 1))
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function answered(message) {
|
|
161
|
+
if (root.token === 0 || message.token !== root.token)
|
|
162
|
+
return
|
|
163
|
+
root.token = 0
|
|
164
|
+
root.answer = message.state
|
|
165
|
+
root.total = message.total || 0
|
|
166
|
+
var rows = message.lines || []
|
|
167
|
+
for (var i = 0; i < rows.length; i++)
|
|
168
|
+
root.held[message.first + i] = rows[i]
|
|
169
|
+
root.stamp += 1
|
|
170
|
+
// Binary, large and failed are the file's whole answer: nothing more is asked of it until the view starts a new one.
|
|
171
|
+
if (root.settled)
|
|
172
|
+
root.schedule()
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// A pane handoff keeps the engine capability, but disconnects the old backend's request.
|
|
176
|
+
function rebind() {
|
|
177
|
+
root.fresh()
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
onBackendChanged: root.rebind()
|
|
181
|
+
onPathChanged: root.fresh()
|
|
182
|
+
onTextChanged: root.fresh()
|
|
183
|
+
onFromTextChanged: root.fresh()
|
|
184
|
+
onActiveChanged: root.fresh()
|
|
185
|
+
Component.onDestruction: root.retiring = true
|
|
186
|
+
onEngineChanged: root.fresh()
|
|
187
|
+
onLimitChanged: root.schedule()
|
|
188
|
+
onWrapChanged: { view.contentX = 0; root.schedule() }
|
|
189
|
+
|
|
190
|
+
Timer { id: askTimer; interval: 0; onTriggered: root.ask() }
|
|
191
|
+
|
|
192
|
+
Connections {
|
|
193
|
+
target: root.engine ? root.backend : null
|
|
194
|
+
function onCodeResult(message) { root.answered(message) }
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
TextMetrics {
|
|
198
|
+
id: metrics
|
|
199
|
+
font.family: Theme.font.family
|
|
200
|
+
font.pixelSize: root.pixelSize
|
|
201
|
+
text: "0"
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
ListView {
|
|
205
|
+
id: view
|
|
206
|
+
anchors.fill: parent
|
|
207
|
+
clip: true
|
|
208
|
+
interactive: root.scrolls
|
|
209
|
+
flickableDirection: root.wrap ? Flickable.VerticalFlick : Flickable.HorizontalAndVerticalFlick
|
|
210
|
+
contentWidth: root.wrap ? width : Math.max(width, root.widestLine + (root.numbered ? root.gutterWidth : 0))
|
|
211
|
+
cacheBuffer: 0
|
|
212
|
+
boundsBehavior: Flickable.StopAtBounds
|
|
213
|
+
model: root.shown
|
|
214
|
+
header: root.header
|
|
215
|
+
onContentYChanged: root.schedule()
|
|
216
|
+
onHeightChanged: root.schedule()
|
|
217
|
+
|
|
218
|
+
delegate: Item {
|
|
219
|
+
id: line
|
|
220
|
+
required property int index
|
|
221
|
+
readonly property var runs: root.rowAt(line.index + 1)
|
|
222
|
+
width: view.contentWidth
|
|
223
|
+
height: Math.max(body.implicitHeight, root.rowHeight)
|
|
224
|
+
|
|
225
|
+
Text {
|
|
226
|
+
visible: root.numbered
|
|
227
|
+
width: root.gutterWidth
|
|
228
|
+
text: String(line.index + 1)
|
|
229
|
+
horizontalAlignment: Text.AlignRight
|
|
230
|
+
color: Theme.color.muted
|
|
231
|
+
opacity: 0.6
|
|
232
|
+
font.family: Theme.font.family
|
|
233
|
+
font.pixelSize: Theme.font.caption
|
|
234
|
+
textFormat: Text.PlainText
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// corner: file contents are arbitrary text, so every run is escaped and the string holds only the font tags written here.
|
|
238
|
+
Text {
|
|
239
|
+
id: body
|
|
240
|
+
x: root.numbered ? root.gutterWidth : 0
|
|
241
|
+
width: line.width - x
|
|
242
|
+
leftPadding: 2 * metrics.advanceWidth
|
|
243
|
+
text: line.runs ? CodeRuns.styled(line.runs, root.inks) : ""
|
|
244
|
+
color: Theme.color.foreground
|
|
245
|
+
font.family: Theme.font.family
|
|
246
|
+
font.pixelSize: root.pixelSize
|
|
247
|
+
textFormat: Text.StyledText
|
|
248
|
+
wrapMode: root.wrap ? Text.WrapAtWordBoundaryOrAnywhere : Text.NoWrap
|
|
249
|
+
// Keep the complete line; the viewport clips and pans it instead of eliding.
|
|
250
|
+
elide: Text.ElideNone
|
|
251
|
+
onImplicitWidthChanged: root.measureLine(implicitWidth)
|
|
252
|
+
Component.onCompleted: root.measureLine(implicitWidth)
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import QtQuick
|
|
2
|
+
import "." as Flea
|
|
3
|
+
|
|
4
|
+
// The code preview's refusal frame, shared by Quick Look's text pane and Markdown Source.
|
|
5
|
+
Item {
|
|
6
|
+
id: root
|
|
7
|
+
|
|
8
|
+
property bool binary: false
|
|
9
|
+
property bool tooLarge: false
|
|
10
|
+
property bool failed: false
|
|
11
|
+
property string markName: "file"
|
|
12
|
+
// Quick Look places the frame below its bar; Source's host has already set that inset.
|
|
13
|
+
property int topInset: 0
|
|
14
|
+
readonly property string status: root.tooLarge ? "This file is too large to preview." : root.failed ? "This file could not be read." : "ready"
|
|
15
|
+
|
|
16
|
+
Column {
|
|
17
|
+
anchors.horizontalCenter: parent.horizontalCenter
|
|
18
|
+
y: root.topInset + Math.round((parent.height - root.topInset - height) / 2)
|
|
19
|
+
spacing: Theme.spacing.gap
|
|
20
|
+
visible: root.binary || (root.tooLarge && !root.failed)
|
|
21
|
+
|
|
22
|
+
Flea.Glyph {
|
|
23
|
+
anchors.horizontalCenter: parent.horizontalCenter
|
|
24
|
+
maxSize: Theme.stateMarkSize
|
|
25
|
+
width: Theme.stateMarkSize
|
|
26
|
+
height: Theme.stateMarkSize
|
|
27
|
+
name: root.markName
|
|
28
|
+
color: Theme.color.muted
|
|
29
|
+
opacity: 0.7
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
Text {
|
|
33
|
+
anchors.horizontalCenter: parent.horizontalCenter
|
|
34
|
+
text: root.binary ? "binary file" : "too large to preview"
|
|
35
|
+
color: Theme.color.muted
|
|
36
|
+
font.family: Theme.font.family
|
|
37
|
+
font.pixelSize: Theme.font.caption
|
|
38
|
+
textFormat: Text.PlainText
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
Text {
|
|
43
|
+
anchors.horizontalCenter: parent.horizontalCenter
|
|
44
|
+
y: root.topInset + Math.round((parent.height - root.topInset - height) / 2)
|
|
45
|
+
visible: false // A failed preview remains blank.
|
|
46
|
+
text: root.status
|
|
47
|
+
color: Theme.color.muted
|
|
48
|
+
font.family: Theme.font.family
|
|
49
|
+
font.pixelSize: Theme.font.body
|
|
50
|
+
textFormat: Text.PlainText
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import QtQuick
|
|
2
|
+
import qs.Commons
|
|
3
|
+
import "." as Flea
|
|
4
|
+
import "js/Collide.js" as Collide
|
|
5
|
+
import "js/Icons.js" as Icons
|
|
6
|
+
|
|
7
|
+
// One choice for every name a paste or a drop would land on, on ui/TrashConfirm.qml's card, keys and look.
|
|
8
|
+
FocusScope {
|
|
9
|
+
id: root
|
|
10
|
+
anchors.fill: parent
|
|
11
|
+
visible: opened || opacity > 0
|
|
12
|
+
// Closed means no input, even while the fade-out is still drawn.
|
|
13
|
+
enabled: opened
|
|
14
|
+
opacity: 0
|
|
15
|
+
property bool opened: false
|
|
16
|
+
property string titleText: ""
|
|
17
|
+
property var names: []
|
|
18
|
+
property string moreText: ""
|
|
19
|
+
property string focusName: Collide.START
|
|
20
|
+
// Merge is present only when a folder lands on a folder; the second card never offers it.
|
|
21
|
+
property bool showMerge: false
|
|
22
|
+
readonly property string explainText: Collide.EXPLAIN
|
|
23
|
+
readonly property real referenceScale: Collide.cardReferenceScale(Theme.font.bodySmall)
|
|
24
|
+
readonly property real cardPadding: Collide.cardPadding(referenceScale)
|
|
25
|
+
readonly property real cardBottomPadding: Math.round(12 * referenceScale)
|
|
26
|
+
// MergeFolders: the buttons keep 6 px of air over the gap.
|
|
27
|
+
readonly property real buttonsAir: Math.round(6 * referenceScale)
|
|
28
|
+
// The card grows with the labels rather than wrapping one, and Keep both stays the default with the ring.
|
|
29
|
+
readonly property real contentWidth: Collide.cardContentWidth(referenceScale, Theme.dialogWidthRatio, buttons.implicitWidth)
|
|
30
|
+
signal chosen(string choice)
|
|
31
|
+
readonly property var cardItem: card
|
|
32
|
+
readonly property bool titleTruncated: title.truncated
|
|
33
|
+
readonly property bool buttonsFit: buttons.width <= body.holderWidth
|
|
34
|
+
readonly property int explainLines: explain.lineCount
|
|
35
|
+
function buttonItem(name) { return ({cancel: cancelButton, skip: skipButton, keep: keepButton, merge: mergeButton, replace: replaceButton})[name] || null }
|
|
36
|
+
function open(heading, list, more, merge) {
|
|
37
|
+
titleText = heading
|
|
38
|
+
names = list
|
|
39
|
+
moreText = more
|
|
40
|
+
showMerge = merge === true
|
|
41
|
+
// A hidden Merge never holds the ring: the card opens on Keep both either way.
|
|
42
|
+
focusName = Collide.START
|
|
43
|
+
body.contentY = 0
|
|
44
|
+
opened = true
|
|
45
|
+
forceActiveFocus()
|
|
46
|
+
}
|
|
47
|
+
function choose(choice) {
|
|
48
|
+
opened = false
|
|
49
|
+
chosen(choice)
|
|
50
|
+
}
|
|
51
|
+
Flea.Reveal { target: root; shown: root.opened; lift: card }
|
|
52
|
+
// A press lands on its own button first, so the accent never shows one choice while another is taken.
|
|
53
|
+
function press(choice) {
|
|
54
|
+
focusName = choice
|
|
55
|
+
choose(choice)
|
|
56
|
+
}
|
|
57
|
+
Keys.onPressed: function(event) {
|
|
58
|
+
if (event.key === Qt.Key_Escape) root.choose("cancel")
|
|
59
|
+
else if (event.modifiers & (Qt.ControlModifier | Qt.AltModifier | Qt.MetaModifier)) { event.accepted = true; return }
|
|
60
|
+
else if (Collide.activates(event.key)) root.choose(root.focusName)
|
|
61
|
+
else root.focusName = Collide.moved(root.focusName, event.key, root.showMerge, event.modifiers)
|
|
62
|
+
if (root.opened) body.reveal(root.buttonItem(root.focusName))
|
|
63
|
+
event.accepted = true
|
|
64
|
+
}
|
|
65
|
+
Flea.DialogScrim {
|
|
66
|
+
onDismissed: root.choose("cancel")
|
|
67
|
+
}
|
|
68
|
+
Rectangle {
|
|
69
|
+
id: card
|
|
70
|
+
x: Theme.cardOrigin(root.width, width)
|
|
71
|
+
y: Theme.cardOrigin(root.height, height)
|
|
72
|
+
width: Theme.cardSpan(root.contentWidth + 2 * root.cardPadding + 2 * Theme.spacing.hairline, root.width - 2 * Theme.spacing.gap)
|
|
73
|
+
height: Theme.cardSpan(body.wanted + root.cardPadding + root.cardBottomPadding + 2 * Theme.spacing.hairline, root.height - 2 * Theme.spacing.gap)
|
|
74
|
+
color: Theme.color.surface
|
|
75
|
+
border.color: Theme.color.mutedFrame
|
|
76
|
+
border.width: Theme.spacing.hairline
|
|
77
|
+
radius: Style.cornerRadius
|
|
78
|
+
MouseArea {
|
|
79
|
+
anchors.fill: parent
|
|
80
|
+
hoverEnabled: true
|
|
81
|
+
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
|
82
|
+
onWheel: function(wheel) { wheel.accepted = true }
|
|
83
|
+
}
|
|
84
|
+
Flea.CardFrame {
|
|
85
|
+
id: body
|
|
86
|
+
bleed: Theme.focusClearance
|
|
87
|
+
anchors.fill: parent
|
|
88
|
+
anchors.leftMargin: root.cardPadding + Theme.spacing.hairline - Theme.focusClearance
|
|
89
|
+
anchors.rightMargin: root.cardPadding + Theme.spacing.hairline - Theme.focusClearance
|
|
90
|
+
anchors.topMargin: root.cardPadding + Theme.spacing.hairline - Theme.focusClearance
|
|
91
|
+
anchors.bottomMargin: root.cardBottomPadding + Theme.spacing.hairline - Theme.focusClearance
|
|
92
|
+
title: Flea.DialogHeader {
|
|
93
|
+
id: title
|
|
94
|
+
width: parent.width
|
|
95
|
+
text: root.titleText
|
|
96
|
+
}
|
|
97
|
+
buttons: Row {
|
|
98
|
+
id: buttons
|
|
99
|
+
anchors.right: parent.right
|
|
100
|
+
topPadding: root.buttonsAir
|
|
101
|
+
spacing: Theme.spacing.gap
|
|
102
|
+
Flea.DialogButton { id: cancelButton; label: Collide.LABELS.cancel; focused: root.focusName === "cancel"; onActivated: root.press("cancel") }
|
|
103
|
+
Flea.DialogButton { id: skipButton; label: Collide.LABELS.skip; focused: root.focusName === "skip"; onActivated: root.press("skip") }
|
|
104
|
+
Flea.DialogButton { id: keepButton; label: Collide.LABELS.keep; primary: true; focused: root.focusName === "keep"; onActivated: root.press("keep") }
|
|
105
|
+
Flea.DialogButton { id: mergeButton; visible: root.showMerge; label: Collide.LABELS.merge; focused: root.focusName === "merge"; onActivated: root.press("merge") }
|
|
106
|
+
Flea.DialogButton { id: replaceButton; label: Collide.LABELS.replace; destructive: true; focused: root.focusName === "replace"; onActivated: root.press("replace") }
|
|
107
|
+
}
|
|
108
|
+
Column {
|
|
109
|
+
width: parent.width
|
|
110
|
+
spacing: Theme.spacing.gap
|
|
111
|
+
Column {
|
|
112
|
+
width: parent.width
|
|
113
|
+
Repeater {
|
|
114
|
+
model: root.names
|
|
115
|
+
delegate: Row {
|
|
116
|
+
id: nameRow
|
|
117
|
+
required property var modelData
|
|
118
|
+
width: parent.width
|
|
119
|
+
height: Theme.fileRowHeight
|
|
120
|
+
spacing: Theme.spacing.gap
|
|
121
|
+
Flea.Glyph { width: Theme.markSize; height: parent.height; name: nameRow.modelData.d ? "folder" : Icons.glyphFor(nameRow.modelData.i); color: Theme.color.foreground }
|
|
122
|
+
Text { width: Math.max(0, parent.width - Theme.markSize - parent.spacing); anchors.verticalCenter: parent.verticalCenter; text: nameRow.modelData.n; textFormat: Text.PlainText; elide: Text.ElideRight; color: Theme.color.foreground; font { family: Theme.font.family; pixelSize: Theme.font.body } }
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
Text {
|
|
126
|
+
width: parent.width
|
|
127
|
+
visible: root.moreText.length > 0
|
|
128
|
+
text: root.moreText
|
|
129
|
+
textFormat: Text.PlainText
|
|
130
|
+
elide: Text.ElideRight
|
|
131
|
+
color: Theme.color.foreground
|
|
132
|
+
font { family: Theme.font.family; pixelSize: Theme.font.caption }
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
Text {
|
|
136
|
+
id: explain
|
|
137
|
+
width: parent.width
|
|
138
|
+
text: root.explainText
|
|
139
|
+
textFormat: Text.PlainText
|
|
140
|
+
wrapMode: Text.Wrap
|
|
141
|
+
color: Theme.color.foreground
|
|
142
|
+
font { family: Theme.font.family; pixelSize: Theme.font.caption }
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import QtQuick
|
|
2
|
+
import "js/Clipboard.js" as Clipboard
|
|
3
|
+
import "js/Collide.js" as Collide
|
|
4
|
+
|
|
5
|
+
// A pane's question before a transfer lands on names that exist: the transfer waits here, so Cancel sends nothing.
|
|
6
|
+
Loader {
|
|
7
|
+
id: root
|
|
8
|
+
required property var pane
|
|
9
|
+
anchors.fill: parent
|
|
10
|
+
z: 2
|
|
11
|
+
// Built by the first question that collides, see AGENTS.md rule 6: a hidden card is not a free one.
|
|
12
|
+
active: false
|
|
13
|
+
source: "CollideConfirm.qml"
|
|
14
|
+
readonly property bool opened: item !== null && item.opened
|
|
15
|
+
// The transfer waiting on the answer, or null, and whether sending it spends a cut clipboard.
|
|
16
|
+
property var pending: null
|
|
17
|
+
property bool spendsCut: false
|
|
18
|
+
property var cutClipboard: null
|
|
19
|
+
property int askId: 0
|
|
20
|
+
// A merge holds its transfer across two cards: the walk's answer lands on the second.
|
|
21
|
+
property bool merging: false
|
|
22
|
+
property var outerNames: []
|
|
23
|
+
// How many names the first card counted, of which outerNames shows at most three.
|
|
24
|
+
property int outerTotal: 0
|
|
25
|
+
property var probe: null
|
|
26
|
+
// Built by the first FAT answer, with no placeholder: a Loader here would stand at startup for a card most windows never open.
|
|
27
|
+
property var fatCard: null
|
|
28
|
+
|
|
29
|
+
// A cut is spent when its transfer goes out, so a Cancel leaves it on the clipboard to paste elsewhere.
|
|
30
|
+
function ask(request, probe, cut) {
|
|
31
|
+
var refused = Collide.refusal(root.opened, root.pending)
|
|
32
|
+
if (refused.length > 0) {
|
|
33
|
+
root.pane.message(refused, false)
|
|
34
|
+
return false
|
|
35
|
+
}
|
|
36
|
+
root.askId += 1
|
|
37
|
+
// Its rows keep the numbering they were read in, so a listing landing before the answer gets the transfer refused, not resolved anew.
|
|
38
|
+
root.pending = Collide.waiting(request, root.pane.backend.heldListing)
|
|
39
|
+
root.spendsCut = cut === true
|
|
40
|
+
root.cutClipboard = cut === true ? root.pane.clipboard : null
|
|
41
|
+
root.merging = false
|
|
42
|
+
root.outerNames = []
|
|
43
|
+
root.probe = probe || null
|
|
44
|
+
root.pane.backend.send(Collide.question(root.pending, probe, root.askId))
|
|
45
|
+
return true
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// A merge's terminal line; only a merge this card asked carries into, so every other line is the pane's own.
|
|
49
|
+
function doneLine(transfer, result) {
|
|
50
|
+
return Collide.doneLine(transfer, result)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Nothing collided: the transfer goes out as it would have, carrying the refusal for any late name.
|
|
54
|
+
function answered(id, total, names, mergeable) {
|
|
55
|
+
if (id !== root.askId || root.pending === null)
|
|
56
|
+
return
|
|
57
|
+
if (total === 0) {
|
|
58
|
+
root.decide(Collide.NONE)
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
root.outerNames = names
|
|
62
|
+
root.outerTotal = total
|
|
63
|
+
root.active = true
|
|
64
|
+
// Paste as links never merges: the Merge card is the transfer's own second card.
|
|
65
|
+
root.item.open(Collide.title(names, total, root.pending.dest), names, Collide.more(total, names.length),
|
|
66
|
+
mergeable === true && root.pending.c !== "link")
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// The destination cannot hold some names: Rename and copy or Skip them rides the question again, before any collision is asked.
|
|
70
|
+
function answeredFat(id, renames, fstype, volume) {
|
|
71
|
+
if (id !== root.askId || root.pending === null)
|
|
72
|
+
return
|
|
73
|
+
if (root.fatCard === null) {
|
|
74
|
+
root.fatCard = Qt.createComponent("FatNamesConfirm.qml").createObject(root.parent, { z: root.z })
|
|
75
|
+
root.fatCard.chosen.connect(root.decideFat)
|
|
76
|
+
}
|
|
77
|
+
root.fatCard.open(Collide.cardTitle(renames.length, volume, fstype), renames, Collide.cardNote(fstype))
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function decideFat(choice) {
|
|
81
|
+
if (choice === "cancel" || root.pending === null) {
|
|
82
|
+
root.decide("cancel")
|
|
83
|
+
} else {
|
|
84
|
+
root.pending.fat = choice
|
|
85
|
+
root.pane.backend.send(Collide.question(root.pending, root.probe, root.askId))
|
|
86
|
+
}
|
|
87
|
+
root.pane.listArea.forceActiveFocus()
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// The second card: what files inside the merging folders already exist, asked by one walk before anything is written.
|
|
91
|
+
function answeredMerge(id, total, names) {
|
|
92
|
+
if (id !== root.askId || root.pending === null || !root.merging)
|
|
93
|
+
return
|
|
94
|
+
if (total === 0) {
|
|
95
|
+
root.decideMerge("refuse")
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
var into = Collide.mergeDest(root.pending, root.outerNames, root.outerTotal)
|
|
99
|
+
root.item.open(Collide.title(names, total, into), names, Collide.more(total, names.length), false)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Merge leaves the first card for the walk: the transfer waits on the second answer, not this one.
|
|
103
|
+
function decide(choice) {
|
|
104
|
+
if (choice === "merge") {
|
|
105
|
+
root.merging = true
|
|
106
|
+
root.pane.backend.send(Collide.mergeQuestion(root.pending, root.probe, root.askId))
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
var request = root.pending
|
|
110
|
+
if (request && choice !== "cancel") {
|
|
111
|
+
// MenuAdditions040: Paste as links asks through this same card.
|
|
112
|
+
root.pane.backend.send(request.c === "link" ? Collide.link(request, choice, root.askId)
|
|
113
|
+
: Collide.transfer(request, choice, root.askId))
|
|
114
|
+
Clipboard.spent(root.pane, root.cutClipboard, root.spendsCut)
|
|
115
|
+
}
|
|
116
|
+
root.pending = null
|
|
117
|
+
root.cutClipboard = null
|
|
118
|
+
root.merging = false
|
|
119
|
+
root.outerNames = []
|
|
120
|
+
root.probe = null
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// The second card's answer rides the merge transfer; Cancel sends nothing and keeps the cut.
|
|
124
|
+
function decideMerge(choice) {
|
|
125
|
+
var request = root.pending
|
|
126
|
+
if (request && choice !== "cancel") {
|
|
127
|
+
root.pane.backend.send(Collide.mergeTransfer(request, choice, root.askId))
|
|
128
|
+
Clipboard.spent(root.pane, root.cutClipboard, root.spendsCut)
|
|
129
|
+
}
|
|
130
|
+
root.pending = null
|
|
131
|
+
root.cutClipboard = null
|
|
132
|
+
root.merging = false
|
|
133
|
+
root.outerNames = []
|
|
134
|
+
root.probe = null
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
Connections {
|
|
138
|
+
target: root.pane.backend
|
|
139
|
+
function onCollisions(id, total, names, mergeable) { root.answered(id, total, names, mergeable) }
|
|
140
|
+
function onMergeCollisions(id, total, names) { root.answeredMerge(id, total, names) }
|
|
141
|
+
function onFatnames(id, renames, fstype, volume) { root.answeredFat(id, renames, fstype, volume) }
|
|
142
|
+
// A dead backend or a refused question ends the wait here and closes the card.
|
|
143
|
+
function onFailed(where, input) {
|
|
144
|
+
if (where === "backend" || Collide.droppedPending(where, input)) {
|
|
145
|
+
root.pending = null
|
|
146
|
+
root.cutClipboard = null
|
|
147
|
+
root.merging = false
|
|
148
|
+
root.outerNames = []
|
|
149
|
+
root.probe = null
|
|
150
|
+
if (root.item)
|
|
151
|
+
root.item.opened = false
|
|
152
|
+
if (root.fatCard !== null)
|
|
153
|
+
root.fatCard.opened = false
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
Connections {
|
|
158
|
+
target: root.item
|
|
159
|
+
function onChosen(choice) {
|
|
160
|
+
if (root.merging)
|
|
161
|
+
root.decideMerge(choice)
|
|
162
|
+
else
|
|
163
|
+
root.decide(choice)
|
|
164
|
+
root.pane.listArea.forceActiveFocus()
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|