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