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
|
@@ -0,0 +1,743 @@
|
|
|
1
|
+
import QtQuick
|
|
2
|
+
import qs.Commons
|
|
3
|
+
import "." as Flea
|
|
4
|
+
import "js/Keymap.js" as Keymap
|
|
5
|
+
import "js/LockedMenu.js" as LockedMenu
|
|
6
|
+
import "js/Menu.js" as Menu
|
|
7
|
+
import "js/MenuContext.js" as MenuContext
|
|
8
|
+
import "js/MenuFit.js" as MenuFit
|
|
9
|
+
import "js/MenuRefresh.js" as MenuRefresh
|
|
10
|
+
|
|
11
|
+
// A plain overlay, not a QQC Popup: the one Controls import cost 10 ms of warm startup.
|
|
12
|
+
Item {
|
|
13
|
+
id: root
|
|
14
|
+
|
|
15
|
+
// Row actions, provider leaves and header choices share this signal, routed by Pane.
|
|
16
|
+
signal chosen(string action)
|
|
17
|
+
signal refused(string reason)
|
|
18
|
+
signal snapshotRequested()
|
|
19
|
+
|
|
20
|
+
property bool opened: false
|
|
21
|
+
property bool preparing: false
|
|
22
|
+
// Driven from ui/Pane.qml's own state, so this file owns no hidden-file logic itself.
|
|
23
|
+
property bool showHidden: false
|
|
24
|
+
// [{id, label}], the reachable Taildrop targets; installed providers keep their disabled reason.
|
|
25
|
+
property var taildropPeers: []
|
|
26
|
+
property bool taildropInstalled: false
|
|
27
|
+
property var localSend: ({ installed: false, peers: [], checking: false })
|
|
28
|
+
property string taildropReason: ""
|
|
29
|
+
property string taildropCode: ""
|
|
30
|
+
property bool providersRefreshing: false
|
|
31
|
+
property bool refreshOwed: false
|
|
32
|
+
property var lastProviderAnswer: null
|
|
33
|
+
// The archive formats this box actually probed, and whether a converter is installed at all.
|
|
34
|
+
property var archiveFormats: []
|
|
35
|
+
property bool canConvert: false
|
|
36
|
+
property bool canExtract: false
|
|
37
|
+
// The cursor row's own name, which is what tells a disk image (lists only) from an archive.
|
|
38
|
+
property string archiveName: ""
|
|
39
|
+
property bool clipboardAvailable: false
|
|
40
|
+
property bool clipboardWatchFailed: false
|
|
41
|
+
// Whether the cursor row is a file, an archive, an image; all decided client-side. Only a file row takes send peers.
|
|
42
|
+
property bool rowIsFile: false
|
|
43
|
+
property bool rowIsArchive: false
|
|
44
|
+
property bool rowIsImage: false
|
|
45
|
+
// Flash to drive reads the name rather than the icon, and a zip's one member once named.
|
|
46
|
+
property string rowName: ""
|
|
47
|
+
property string flashZipMember: ""
|
|
48
|
+
// MenuAdditions040: Show original is visible but only on a symlink.
|
|
49
|
+
property bool rowIsSymlink: false
|
|
50
|
+
// MenuAdditions040 callout 10: the two-byte shebang read of the cursor row at menu open.
|
|
51
|
+
property bool rowHasShebang: false
|
|
52
|
+
// ... and whether the menu's single target is the cursor row itself.
|
|
53
|
+
property bool cursorIsTarget: false
|
|
54
|
+
property int rowMode: 0
|
|
55
|
+
property int selectionCount: 0
|
|
56
|
+
// MenuAdditions040: Permissions takes the whole selection.
|
|
57
|
+
property var selectionModes: []
|
|
58
|
+
// Compare follows held metadata and the matching snapshot while the menu is open.
|
|
59
|
+
property var compareKinds: []
|
|
60
|
+
// OpenWith.html's flyout rows, filled by ui/PaneMenuActions.qml when the registry answers.
|
|
61
|
+
property var openWithApps: []
|
|
62
|
+
property bool openWithLoaded: false
|
|
63
|
+
// The actual account directory is available only after a fresh provider status and identity check.
|
|
64
|
+
property string dropboxPath: ""
|
|
65
|
+
property bool dropboxInstalled: false
|
|
66
|
+
property string dropboxReason: ""
|
|
67
|
+
property string dropboxCode: ""
|
|
68
|
+
// A row already inside the account directory offers a share link instead of another move.
|
|
69
|
+
property bool rowInDropbox: false
|
|
70
|
+
// False on a listing's empty space, where Menus.html's background column is what opens instead.
|
|
71
|
+
// openBackground() is its only writer and openAt() puts it back, because one instance serves both.
|
|
72
|
+
property bool hasRow: true
|
|
73
|
+
// ExtThumbs: src/backend/extclass.rs's word for the directory this opening answers for.
|
|
74
|
+
property string storageClass: ""
|
|
75
|
+
// The Locked tile's folder while one is drawn, "" while none is; bound by ui/Pane.qml. A right
|
|
76
|
+
// click landing on the tile reaches openBackground through the views, which routes it to the
|
|
77
|
+
// locked folder's own menu rather than the parent's background one.
|
|
78
|
+
property string tileTarget: ""
|
|
79
|
+
property int tileMode: 0
|
|
80
|
+
// The folder this opening answers for, captured at open and cleared at close.
|
|
81
|
+
property string lockedPath: ""
|
|
82
|
+
property int lockedMode: 0
|
|
83
|
+
readonly property bool forLocked: root.lockedPath.length > 0
|
|
84
|
+
// The owner's menuSelectionIdentity(), read at open and at a choice only; none, as on the rail, reads "".
|
|
85
|
+
property var identitySource: null
|
|
86
|
+
function selectionIdentity() { return root.identitySource ? root.identitySource.menuSelectionIdentity() : "" }
|
|
87
|
+
property string openedIdentity: ""
|
|
88
|
+
// The owner intersects the live monitor work area with this application's viewport.
|
|
89
|
+
property rect workArea: Qt.rect(0, 0, root.width, root.height)
|
|
90
|
+
readonly property real workAreaInset: Theme.space(4)
|
|
91
|
+
|
|
92
|
+
// The rail's own rows when ui/Sidebar.qml raised this menu, empty when the listing did. One
|
|
93
|
+
// instance serves both: a second one in this tree takes the keyboard from the list, see AGENTS.md.
|
|
94
|
+
property var railEntries: []
|
|
95
|
+
// The key naming the rail row those rows belong to, see ui/js/Mounts.js "railKey": the rail
|
|
96
|
+
// rebuilds on a poll, so an index would name a different row by the time one is chosen.
|
|
97
|
+
property string railKey: ""
|
|
98
|
+
readonly property bool forRail: root.railEntries.length > 0
|
|
99
|
+
signal railChosen(string action, string key)
|
|
100
|
+
// The Locked tile's folder with the row chosen on it, read before close() the way railKey
|
|
101
|
+
// is: close() clears lockedPath, so Pane.qml cannot read it after the menu is gone.
|
|
102
|
+
signal lockedChosen(string action, string path)
|
|
103
|
+
|
|
104
|
+
// ui/Header.qml's own entrance, the third face of this one instance: openForHeader() flips the
|
|
105
|
+
// entries to ui/js/Menu.js headerEntries (the column toggles and the hidden toggle, built from
|
|
106
|
+
// qs module ViewState's hidden columns and the pane's showHidden), and every row flows back
|
|
107
|
+
// through chosen() like the listing's own. A row's chosen verb routes by prefix in ui/Pane.qml.
|
|
108
|
+
property bool forHeader: false
|
|
109
|
+
function openForHeader(scenePoint) {
|
|
110
|
+
root.forHeader = true
|
|
111
|
+
root.place(scenePoint)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// The pane keeps its Keys handler on the list, so the menu has to hand focus back on close.
|
|
115
|
+
property Item focusHolder: null
|
|
116
|
+
// The original focus item may disappear while the menu is open; the owning view is the fallback.
|
|
117
|
+
property Item focusOwner: null
|
|
118
|
+
readonly property bool keyboardFocused: keyCatcher.activeFocus
|
|
119
|
+
|
|
120
|
+
// The keyboard-highlighted top-level row, and which row's flyout is open beside it, or -1.
|
|
121
|
+
property int cursor: 0
|
|
122
|
+
property int openSubmenuRow: -1
|
|
123
|
+
property int submenuCursor: 0
|
|
124
|
+
// A hidden row still opens its flyout from the action.
|
|
125
|
+
property string loneFlyoutAction: ""
|
|
126
|
+
readonly property bool submenuOpen: root.openSubmenuRow >= 0 || root.loneFlyoutAction.length > 0
|
|
127
|
+
// What a closing flyout keeps drawing while it fades out; ui/FlyoutFade.qml holds them at their last open values.
|
|
128
|
+
property var heldRows: []
|
|
129
|
+
property real heldOffset: 0
|
|
130
|
+
property string heldAction: ""
|
|
131
|
+
property var flyoutFade: null
|
|
132
|
+
function submenuAction() {
|
|
133
|
+
return root.loneFlyoutAction.length > 0 ? root.loneFlyoutAction
|
|
134
|
+
: root.entries[root.openSubmenuRow] ? root.entries[root.openSubmenuRow].action : ""
|
|
135
|
+
}
|
|
136
|
+
onSubmenuOpenChanged: if (!root.submenuOpen) MenuRefresh.pressChanged(root, false); else root.buildFlyoutFade()
|
|
137
|
+
// Built by the first flyout, so a menu that never opens one holds neither the fade nor the held values.
|
|
138
|
+
function buildFlyoutFade() {
|
|
139
|
+
if (root.flyoutFade === null)
|
|
140
|
+
root.flyoutFade = Qt.createComponent("FlyoutFade.qml").createObject(root, { menu: root })
|
|
141
|
+
}
|
|
142
|
+
// The glyph every open flyout row draws, read back so a test can name it without OCR.
|
|
143
|
+
function submenuGlyphs() {
|
|
144
|
+
if (!root.submenuOpen)
|
|
145
|
+
return ""
|
|
146
|
+
var mark = Menu.submenuGlyph(root.submenuAction())
|
|
147
|
+
var out = []
|
|
148
|
+
for (var i = 0; i < root.submenuEntries.length; i++) {
|
|
149
|
+
// What the row draws, not what the flyout defaults to: an Open with row carries its own
|
|
150
|
+
// glyph or an application icon, and reporting the default made a check measure nothing.
|
|
151
|
+
var row = root.submenuEntries[i]
|
|
152
|
+
out.push(row.separator === true ? "" : row.icon ? "icon"
|
|
153
|
+
: row.glyph !== undefined ? row.glyph : mark)
|
|
154
|
+
}
|
|
155
|
+
return out.join("|")
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// The open flyout draws the row's entries, or the lone action's leaves.
|
|
159
|
+
readonly property var submenuEntries: root.loneFlyoutAction.length > 0
|
|
160
|
+
? Menu.flyoutEntries(root.loneFlyoutAction)
|
|
161
|
+
: (root.submenuOpen && root.entries[root.openSubmenuRow]
|
|
162
|
+
? root.entries[root.openSubmenuRow].submenu : [])
|
|
163
|
+
|
|
164
|
+
// The row list this menu currently offers; a test reads this back through shell.qml's IPC.
|
|
165
|
+
property var entries: []
|
|
166
|
+
// While a card's rows build its fit reads none, then reads them once when they stand; a closed flyout holds nothing.
|
|
167
|
+
property bool rowsBuilding: false
|
|
168
|
+
property bool submenuBuilding: false
|
|
169
|
+
function setEntries(next, flyoutRow) { try { root.rowsBuilding = true; root.submenuBuilding = root.submenuOpen; root.entries = next; if (flyoutRow !== undefined) root.openSubmenuRow = flyoutRow } finally { root.rowsBuilding = false; root.submenuBuilding = false } }
|
|
170
|
+
property bool canTrash: true
|
|
171
|
+
// False in a read-only folder, off the listing's own w flag; true until the pane knows better.
|
|
172
|
+
property bool dirWritable: true
|
|
173
|
+
// A filesystem that holds no links offers no Paste as rows; true until the pane knows better.
|
|
174
|
+
property bool canLink: true
|
|
175
|
+
// The Tags flyout's rows while a menu is live; null where tags cannot be stored, which drops the row.
|
|
176
|
+
property var tagSubmenu: null
|
|
177
|
+
// Issue 179: the background menu's Sort by flyout offers its forget row only for this folder.
|
|
178
|
+
property bool hasFolderSort: false
|
|
179
|
+
|
|
180
|
+
// Menu.js builds entries from the context shared by the row menu and query; includeHidden is the keymap sheet's.
|
|
181
|
+
function buildEntries(flyoutAction, includeHidden) {
|
|
182
|
+
// Rail rows arrive built with their own release verdicts.
|
|
183
|
+
if (root.forRail)
|
|
184
|
+
return root.railEntries
|
|
185
|
+
if (root.forHeader)
|
|
186
|
+
return Menu.headerEntries(ViewState.hiddenCols, root.showHidden)
|
|
187
|
+
// Locked rows address the denied folder rather than its covered parent.
|
|
188
|
+
if (root.forLocked)
|
|
189
|
+
return LockedMenu.lockedEntries({ lockedMode: root.lockedMode, hiddenActions: ViewState.menuHidden })
|
|
190
|
+
return Menu.listingEntries(root.listingContext(flyoutAction, includeHidden))
|
|
191
|
+
}
|
|
192
|
+
function listingContext(flyoutAction, includeHidden) {
|
|
193
|
+
return MenuContext.listingContext(root, flyoutAction, includeHidden, {
|
|
194
|
+
scripts: Flea.Scripts.entries, hiddenActions: ViewState.menuHidden,
|
|
195
|
+
langMarks: ViewState.langMarks,
|
|
196
|
+
thumbPreview: ViewState.preview, updateVersion: UpdateCheck.menuVersion
|
|
197
|
+
})
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// The row item at an index, for ui/Ipc.qml: a driven test clicks a menu row without deriving its geometry from a row count the Menus settings can now change under it.
|
|
201
|
+
function itemFor(index) { return menuRows.itemAt(index) }
|
|
202
|
+
function submenuItemFor(index) { return subRows.itemAt(index) }
|
|
203
|
+
readonly property var frameItem: frame
|
|
204
|
+
readonly property var submenuFrameItem: flyout
|
|
205
|
+
|
|
206
|
+
// A separator is never the cursor, so both key steps and the opening cursor skip over one.
|
|
207
|
+
function stepCursor(from, delta) { return Menu.stepRow(root.entries, from, delta) }
|
|
208
|
+
// The same rule inside a flyout: OpenWith.html's tail row sits under its own separator.
|
|
209
|
+
function stepSubmenu(from, delta) { return Menu.stepRow(root.submenuEntries, from, delta) }
|
|
210
|
+
// A wheel over the main frame closes the flyout first, the same path moving the pointer
|
|
211
|
+
// onto a plain row takes, and then steps; the highlight never moves where it is not drawn.
|
|
212
|
+
function stepMain(delta) {
|
|
213
|
+
root.openSubmenuRow = -1
|
|
214
|
+
root.loneFlyoutAction = ""
|
|
215
|
+
root.cursor = root.stepCursor(root.cursor, delta)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function firstRow() {
|
|
219
|
+
return root.stepCursor(-1, 1)
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
anchors.fill: parent
|
|
223
|
+
// The frames fade out after opened flips (ui/Reveal.qml), so the menu stays drawn until both are gone and takes no input meanwhile.
|
|
224
|
+
visible: root.opened || frame.opacity > 0 || flyout.opacity > 0
|
|
225
|
+
enabled: root.opened
|
|
226
|
+
z: 1
|
|
227
|
+
|
|
228
|
+
// Built by the first open, so a pane that never opens a menu holds no animation (the first frame's cost).
|
|
229
|
+
property var fade: null
|
|
230
|
+
onOpenedChanged: {
|
|
231
|
+
if (root.opened && root.fade === null)
|
|
232
|
+
root.fade = Qt.createComponent("Reveal.qml").createObject(root, { target: frame, shown: Qt.binding(function () { return root.opened }) })
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Takes a point in scene coordinates and keeps the whole menu inside the pane it belongs to.
|
|
236
|
+
function openAt(scenePoint) {
|
|
237
|
+
root.clearRail()
|
|
238
|
+
root.forHeader = false
|
|
239
|
+
root.hasRow = true
|
|
240
|
+
root.place(scenePoint)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Empty-space clicks draw background entries, or the Locked tile's own folder menu.
|
|
244
|
+
function openBackground(scenePoint) {
|
|
245
|
+
if (root.tileTarget.length > 0) {
|
|
246
|
+
root.openLocked(root.tileTarget, root.tileMode, scenePoint)
|
|
247
|
+
return
|
|
248
|
+
}
|
|
249
|
+
root.clearRail()
|
|
250
|
+
root.forHeader = false
|
|
251
|
+
root.hasRow = false
|
|
252
|
+
root.place(scenePoint)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// The Locked tile's own entrance, capturing the folder this opening answers for; every row
|
|
256
|
+
// below acts on that folder alone, through ui/Pane.qml's locked dispatch rather than the
|
|
257
|
+
// snapshot the cursor rows take.
|
|
258
|
+
function openLocked(path, mode, scenePoint) {
|
|
259
|
+
// An empty locked menu opens no frame and closes a stale one, so a refusal leaves no actionable frame standing.
|
|
260
|
+
var refusal = LockedMenu.lockedRefusal({ lockedMode: mode, hiddenActions: ViewState.menuHidden })
|
|
261
|
+
if (refusal.length > 0) { root.close(); root.refused(refusal); return }
|
|
262
|
+
root.clearRail()
|
|
263
|
+
root.forHeader = false
|
|
264
|
+
root.hasRow = false
|
|
265
|
+
root.lockedPath = path
|
|
266
|
+
root.lockedMode = mode
|
|
267
|
+
root.place(scenePoint)
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// ui/Sidebar.qml's own entrance to this same menu: the rail hands in its rows and the key that
|
|
271
|
+
// names the row they came from, and a rail row with nothing to release opens no menu at all.
|
|
272
|
+
function openForRail(key, entries, scenePoint) {
|
|
273
|
+
if (!entries || entries.length === 0)
|
|
274
|
+
return
|
|
275
|
+
root.railKey = key
|
|
276
|
+
root.railEntries = entries
|
|
277
|
+
root.place(scenePoint)
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Cleared on both ends: a rail entry left standing would put Eject on a listing row's menu,
|
|
281
|
+
// and a locked path left standing would put the old folder's rows on another directory's tile.
|
|
282
|
+
function clearRail() {
|
|
283
|
+
root.railEntries = []
|
|
284
|
+
root.railKey = ""
|
|
285
|
+
root.lockedPath = ""
|
|
286
|
+
root.lockedMode = 0
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Where the menu was asked to open, in this item's own coordinates; clampFrame runs twice on it.
|
|
290
|
+
property real placeX: 0
|
|
291
|
+
property real placeY: 0
|
|
292
|
+
|
|
293
|
+
// A Column hands its implicitHeight to the frame one polish after its model changes, so the
|
|
294
|
+
// height place() reads is still the menu that was open before this one. Clamping again on the
|
|
295
|
+
// real height lands before the first paint, so no menu is placed against another's size.
|
|
296
|
+
function clampFrame() {
|
|
297
|
+
frame.x = root.workArea.x + Menu.clamp(root.placeX - root.workArea.x, frame.width, root.workArea.width)
|
|
298
|
+
frame.y = root.workArea.y + root.workAreaInset
|
|
299
|
+
+ Menu.clamp(root.placeY - root.workArea.y - root.workAreaInset,
|
|
300
|
+
frame.height, Math.max(0, root.workArea.height - 2 * root.workAreaInset))
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// The scene point any row or the ground last saw, so a row tells a moving pointer from one it arrived under.
|
|
304
|
+
property point pointerGlobal: Qt.point(-1, -1)
|
|
305
|
+
// Placing to its first frame's afterAnimating: Qt hovers what that frame shows, kept rows too, so a "move" then is the rest point; Qt 6.12 can hover later, which ui/MenuRow.qml reads as rest.
|
|
306
|
+
property bool pointerSettling: false
|
|
307
|
+
Connections {
|
|
308
|
+
target: root.pointerSettling ? root.Window.window : null
|
|
309
|
+
function onAfterAnimating() { root.pointerSettling = false }
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function place(scenePoint) {
|
|
313
|
+
root.refreshOwed = false
|
|
314
|
+
root.preparing = true
|
|
315
|
+
if (!root.opened)
|
|
316
|
+
root.focusHolder = root.Window.window ? root.Window.window.activeFocusItem : null
|
|
317
|
+
root.pointerGlobal = Qt.point(-1, -1)
|
|
318
|
+
root.pointerSettling = true
|
|
319
|
+
// A place that changes nothing drawn schedules no frame, so it asks for the one that ends the settle.
|
|
320
|
+
if (root.Window.window) root.Window.window.update()
|
|
321
|
+
var point = root.mapFromItem(null, scenePoint)
|
|
322
|
+
root.placeX = point.x
|
|
323
|
+
root.placeY = point.y
|
|
324
|
+
root.setEntries(root.buildEntries())
|
|
325
|
+
root.openedIdentity = root.selectionIdentity()
|
|
326
|
+
root.loneFlyoutAction = ""
|
|
327
|
+
scroll.contentY = 0
|
|
328
|
+
scroll.resetSteps()
|
|
329
|
+
subScroll.resetSteps()
|
|
330
|
+
root.clampFrame()
|
|
331
|
+
root.cursor = root.firstRow()
|
|
332
|
+
root.openSubmenuRow = -1
|
|
333
|
+
root.submenuCursor = 0
|
|
334
|
+
root.opened = true
|
|
335
|
+
root.preparing = false
|
|
336
|
+
if (root.hasRow && !root.forRail && !root.forHeader) root.snapshotRequested()
|
|
337
|
+
keyCatcher.forceActiveFocus()
|
|
338
|
+
}
|
|
339
|
+
onWorkAreaChanged: if (root.opened) root.clampFrame()
|
|
340
|
+
onCursorChanged: scroll.reveal(menuRows.itemAt(root.cursor))
|
|
341
|
+
onSubmenuCursorChanged: subScroll.reveal(subRows.itemAt(root.submenuCursor))
|
|
342
|
+
|
|
343
|
+
// Every wheel scroll calls this, so a shut menu costs nothing and never touches focus.
|
|
344
|
+
function close() {
|
|
345
|
+
root.refreshOwed = false
|
|
346
|
+
if (!root.opened)
|
|
347
|
+
return
|
|
348
|
+
root.opened = false
|
|
349
|
+
root.openSubmenuRow = -1
|
|
350
|
+
root.loneFlyoutAction = ""
|
|
351
|
+
root.clearRail()
|
|
352
|
+
var holder = root.focusHolder && root.focusHolder.visible && root.focusHolder.enabled ? root.focusHolder : root.focusOwner
|
|
353
|
+
if (holder)
|
|
354
|
+
holder.forceActiveFocus()
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// The menu closes before the action runs, so it never hangs over the listing that action opened.
|
|
358
|
+
function choose(action) {
|
|
359
|
+
if (!root.validateChoice(action, "")) return
|
|
360
|
+
// Both read before close(), which is what clears the rail rows and the locked path.
|
|
361
|
+
var key = root.railKey
|
|
362
|
+
var rail = root.forRail
|
|
363
|
+
var locked = root.lockedPath
|
|
364
|
+
root.close()
|
|
365
|
+
if (rail) {
|
|
366
|
+
root.railChosen(action, key)
|
|
367
|
+
return
|
|
368
|
+
}
|
|
369
|
+
if (locked.length > 0) {
|
|
370
|
+
root.lockedChosen(action, locked)
|
|
371
|
+
return
|
|
372
|
+
}
|
|
373
|
+
root.chosen(action)
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// One signal covers every submenu: the row's own action, a colon, and the entry chosen inside it.
|
|
377
|
+
function chooseSub(id) {
|
|
378
|
+
var entry = root.entries[root.openSubmenuRow]
|
|
379
|
+
var action = root.loneFlyoutAction || (entry ? entry.action : "")
|
|
380
|
+
if (root.loneFlyoutAction.length > 0) {
|
|
381
|
+
var lonePick = Menu.loneChoice(root.loneFlyoutAction, id, root.forRail, root.forHeader, root.hasRow, root.openedIdentity, root.selectionIdentity())
|
|
382
|
+
if (lonePick.kind !== "fire") {
|
|
383
|
+
root.refuseLone(lonePick.kind)
|
|
384
|
+
return
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
if (!action || !root.validateChoice(action, id)) return
|
|
388
|
+
// A Tags choice changes the boxes this flyout draws, so the menu stays up and the answer redraws them in place.
|
|
389
|
+
if (action !== "tags") root.close()
|
|
390
|
+
root.chosen(action + ":" + id)
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function openSubmenu(index) {
|
|
394
|
+
root.loneFlyoutAction = ""
|
|
395
|
+
if (!Menu.hasSubmenu(root.entries[index]) || root.entries[index].disabled === true) return
|
|
396
|
+
root.submenuBuilding = true
|
|
397
|
+
try { root.openSubmenuRow = index } finally { root.submenuBuilding = false }
|
|
398
|
+
root.submenuCursor = 0
|
|
399
|
+
subScroll.contentY = 0
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// c and P open Copy as and Paste as with the flyout already open.
|
|
403
|
+
function openSubmenuFor(action) {
|
|
404
|
+
var leaves = Menu.flyoutEntries(action)
|
|
405
|
+
if (!leaves.length) return false
|
|
406
|
+
if (action === "pasteAs" && !root.clipboardAvailable) {
|
|
407
|
+
root.close()
|
|
408
|
+
root.refused(Menu.EMPTY_CLIPBOARD)
|
|
409
|
+
return false
|
|
410
|
+
}
|
|
411
|
+
if (!root.validateChoice(action, leaves[0].id)) return false
|
|
412
|
+
var pick = Menu.submenuFor(action, root.entries, root.clipboardAvailable)
|
|
413
|
+
if (pick.kind === "row") {
|
|
414
|
+
root.cursor = pick.index
|
|
415
|
+
root.openSubmenu(pick.index)
|
|
416
|
+
return true
|
|
417
|
+
}
|
|
418
|
+
if (pick.kind === "lone") {
|
|
419
|
+
root.submenuBuilding = true
|
|
420
|
+
try { root.openSubmenuRow = -1; root.loneFlyoutAction = action } finally { root.submenuBuilding = false }
|
|
421
|
+
root.submenuCursor = 0
|
|
422
|
+
subScroll.contentY = 0
|
|
423
|
+
return true
|
|
424
|
+
}
|
|
425
|
+
if (pick.kind === "refuse") {
|
|
426
|
+
root.close()
|
|
427
|
+
root.refused(Menu.EMPTY_CLIPBOARD)
|
|
428
|
+
return false
|
|
429
|
+
}
|
|
430
|
+
return false
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// Fresh capabilities use the normal inventory; selection stays on its action and placement uses the existing clamp.
|
|
434
|
+
function refreshProviderRows() {
|
|
435
|
+
if (!root.opened || root.forRail || root.forHeader || root.forLocked) return
|
|
436
|
+
// Replacing a pressed delegate destroys its grab before release can activate it.
|
|
437
|
+
if (MenuRefresh.anyPressed(menuRows, root.submenuOpen ? subRows : null)) {
|
|
438
|
+
root.refreshOwed = true
|
|
439
|
+
return
|
|
440
|
+
}
|
|
441
|
+
root.refreshOwed = false
|
|
442
|
+
var next = root.buildEntries()
|
|
443
|
+
// An answer that changed nothing drawn leaves every row standing: no model reset, no cursor move.
|
|
444
|
+
if (MenuRefresh.unchanged(root.entries, next)) return
|
|
445
|
+
MenuRefresh.apply(root, next)
|
|
446
|
+
}
|
|
447
|
+
// A finished refresh: its answer is what later opens draw while their own refresh runs behind them, see ui/js/MenuRefresh.js.
|
|
448
|
+
function providersSettled() {
|
|
449
|
+
root.lastProviderAnswer = MenuRefresh.settle(MenuRefresh.live(root))
|
|
450
|
+
root.refreshProviderRows()
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function refuseLone(kind) {
|
|
454
|
+
root.close()
|
|
455
|
+
root.refused(kind === "moved" ? "Selected items changed; reopen the menu."
|
|
456
|
+
: "That action is no longer available; reopen the menu.")
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// Rebuild only to validate; rows stay fixed while the menu is open under the pointer.
|
|
460
|
+
function validateChoice(action, subId, includeHidden) {
|
|
461
|
+
return MenuContext.validateChoice(root, action, subId, includeHidden)
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// Offsets are summed, not multiplied; a lone flyout stands at the top.
|
|
465
|
+
function submenuOffset() {
|
|
466
|
+
if (root.loneFlyoutAction.length > 0)
|
|
467
|
+
return 0
|
|
468
|
+
var y = 0
|
|
469
|
+
for (var i = 0; i < root.openSubmenuRow; i++)
|
|
470
|
+
y += root.entries[i].separator === true ? separatorProbe.separatorHeight : Theme.rowHeight
|
|
471
|
+
return y - scroll.contentY
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// One row off the model, only so the two heights above are read from MenuRow rather than repeated here.
|
|
475
|
+
Flea.MenuRow {
|
|
476
|
+
id: separatorProbe
|
|
477
|
+
visible: false
|
|
478
|
+
entry: ({ separator: true })
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// The ground owns every pointer event outside the rows: hover stops here, the wheel is swallowed, and the click that closes is taken on release so the row beneath never sees a press the close would have handed it.
|
|
482
|
+
MouseArea {
|
|
483
|
+
id: ground
|
|
484
|
+
anchors.fill: parent
|
|
485
|
+
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
|
486
|
+
hoverEnabled: true
|
|
487
|
+
onEntered: root.pointerGlobal = ground.mapToItem(null, ground.mouseX, ground.mouseY)
|
|
488
|
+
onPositionChanged: function (mouse) { root.pointerGlobal = ground.mapToItem(null, mouse.x, mouse.y) }
|
|
489
|
+
onClicked: root.close()
|
|
490
|
+
onWheel: function (wheel) { wheel.accepted = true }
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// How far an edge fade reaches past the card's padding, as a share of a row, so it covers the first cut row without washing a whole one.
|
|
494
|
+
readonly property real fadeRowShare: 0.7
|
|
495
|
+
readonly property real fadeReach: Math.round(Theme.rowHeight * root.fadeRowShare)
|
|
496
|
+
// The widest row's wanted width in a card's column; a binding that calls it follows every row's own text.
|
|
497
|
+
function widestRow(column) { return MenuFit.widestWanted(column.children) }
|
|
498
|
+
|
|
499
|
+
Rectangle {
|
|
500
|
+
id: frame
|
|
501
|
+
opacity: 0
|
|
502
|
+
// Theme.menuWidth, or the widest row's own width when a label and its hint need more, never past the work area.
|
|
503
|
+
width: Math.max(0, Math.min(root.workArea.width, root.rowsBuilding ? Theme.menuWidth : Math.max(Theme.menuWidth, root.widestRow(rows))))
|
|
504
|
+
onWidthChanged: if (root.opened) root.clampFrame()
|
|
505
|
+
// The vertical inset keeps the first and last row's square highlight off the rounded corners.
|
|
506
|
+
height: Math.max(0, Math.min(rows.implicitHeight + 2 * Theme.spacing.rowPaddingY,
|
|
507
|
+
root.workArea.height - 2 * root.workAreaInset))
|
|
508
|
+
// The height this menu is actually going to have, arriving after place() has already run.
|
|
509
|
+
onHeightChanged: if (root.opened) root.clampFrame()
|
|
510
|
+
color: Theme.color.surface
|
|
511
|
+
border.width: Theme.spacing.hairline
|
|
512
|
+
border.color: Theme.color.mutedFrame
|
|
513
|
+
// Mirrors hyprland decoration:rounding, same as NetworkDialog; 0 on a stock box stays square.
|
|
514
|
+
radius: Style.cornerRadius
|
|
515
|
+
|
|
516
|
+
// The card takes every press no row takes (padding, separator, disabled row); a stepped body is no Flickable, so the closing ground would.
|
|
517
|
+
MouseArea { anchors.fill: parent; acceptedButtons: Qt.LeftButton | Qt.RightButton }
|
|
518
|
+
|
|
519
|
+
Flea.CardScroll {
|
|
520
|
+
id: scroll
|
|
521
|
+
// A menu steps the highlight, never pixel scrolls: one row a notch, one row per row height of touchpad travel. No bar, no lane.
|
|
522
|
+
highlightSteps: true
|
|
523
|
+
stepBy: function (delta) { root.stepMain(delta) }
|
|
524
|
+
revealClearY: root.fadeReach
|
|
525
|
+
// A rebuilt model keeps the flyout's row, else the cursor's, in view.
|
|
526
|
+
onContentHeightChanged: if (root.opened) scroll.reveal(menuRows.itemAt(root.openSubmenuRow >= 0 ? root.openSubmenuRow : root.cursor))
|
|
527
|
+
anchors.fill: parent
|
|
528
|
+
anchors.topMargin: Theme.spacing.rowPaddingY
|
|
529
|
+
anchors.bottomMargin: Theme.spacing.rowPaddingY
|
|
530
|
+
Column {
|
|
531
|
+
id: rows
|
|
532
|
+
width: parent.width
|
|
533
|
+
|
|
534
|
+
Repeater {
|
|
535
|
+
id: menuRows
|
|
536
|
+
model: root.entries
|
|
537
|
+
delegate: Flea.MenuRow {
|
|
538
|
+
id: row
|
|
539
|
+
required property var modelData
|
|
540
|
+
required property int index
|
|
541
|
+
width: rows.width
|
|
542
|
+
entry: row.modelData
|
|
543
|
+
onPressedChanged: MenuRefresh.pressChanged(root, row.pressed)
|
|
544
|
+
current: !root.submenuOpen && root.cursor === row.index
|
|
545
|
+
lastPointerGlobal: root.pointerGlobal
|
|
546
|
+
onPointerSeen: function (at) { root.pointerGlobal = at }
|
|
547
|
+
onPointerMoved: {
|
|
548
|
+
if (root.pointerSettling) return
|
|
549
|
+
root.cursor = row.index
|
|
550
|
+
if (Menu.hasSubmenu(row.modelData)) root.openSubmenu(row.index)
|
|
551
|
+
else { root.openSubmenuRow = -1; root.loneFlyoutAction = "" }
|
|
552
|
+
}
|
|
553
|
+
onActivated: {
|
|
554
|
+
if (Menu.hasSubmenu(row.modelData))
|
|
555
|
+
root.openSubmenu(row.index)
|
|
556
|
+
else
|
|
557
|
+
root.choose(row.modelData.action)
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
Flea.MenuEdgeFade {
|
|
564
|
+
anchors.top: parent.top
|
|
565
|
+
inset: Theme.spacing.rowPaddingY
|
|
566
|
+
reach: root.fadeReach
|
|
567
|
+
visible: scroll.contentY > 0
|
|
568
|
+
}
|
|
569
|
+
Flea.MenuEdgeFade {
|
|
570
|
+
anchors.bottom: parent.bottom
|
|
571
|
+
inset: Theme.spacing.rowPaddingY
|
|
572
|
+
reach: root.fadeReach
|
|
573
|
+
visible: scroll.contentY + scroll.height < scroll.contentHeight
|
|
574
|
+
rotation: 180
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// The flyout: a second frame beside whichever row opened it, only while one has, at least its parent's width.
|
|
579
|
+
Rectangle {
|
|
580
|
+
id: flyout
|
|
581
|
+
visible: root.submenuOpen || flyout.opacity > 0
|
|
582
|
+
enabled: root.submenuOpen
|
|
583
|
+
opacity: 0
|
|
584
|
+
x: frame.x + frame.width + width <= root.workArea.x + root.workArea.width
|
|
585
|
+
? frame.x + frame.width : Math.max(root.workArea.x, frame.x - width)
|
|
586
|
+
// peers.y already carries the inset, so the flyout frame itself stays on the row grid.
|
|
587
|
+
y: Math.max(root.workArea.y + root.workAreaInset,
|
|
588
|
+
Math.min(frame.y + root.heldOffset, root.workArea.y + root.workArea.height - root.workAreaInset - height))
|
|
589
|
+
// Its own read, so a change of the parent's width does not read every peer's width again.
|
|
590
|
+
readonly property real widestPeer: root.submenuBuilding ? 0 : root.widestRow(peers)
|
|
591
|
+
width: Math.max(0, Math.min(Math.max(frame.width, Theme.menuWidth, flyout.widestPeer), root.workArea.width))
|
|
592
|
+
height: Math.max(0, Math.min(peers.implicitHeight + 2 * Theme.spacing.rowPaddingY,
|
|
593
|
+
root.workArea.height - 2 * root.workAreaInset))
|
|
594
|
+
color: Theme.color.surface
|
|
595
|
+
border.width: Theme.spacing.hairline
|
|
596
|
+
border.color: Theme.color.mutedFrame
|
|
597
|
+
radius: Style.cornerRadius
|
|
598
|
+
|
|
599
|
+
// The flyout takes its dead presses the same way.
|
|
600
|
+
MouseArea { anchors.fill: parent; acceptedButtons: Qt.LeftButton | Qt.RightButton }
|
|
601
|
+
|
|
602
|
+
Flea.CardScroll {
|
|
603
|
+
id: subScroll
|
|
604
|
+
// The flyout steps like the main frame, through its own cursor and reveal.
|
|
605
|
+
highlightSteps: true
|
|
606
|
+
stepBy: function (delta) { root.submenuCursor = root.stepSubmenu(root.submenuCursor, delta) }
|
|
607
|
+
revealClearY: root.fadeReach
|
|
608
|
+
anchors.fill: parent
|
|
609
|
+
anchors.topMargin: Theme.spacing.rowPaddingY
|
|
610
|
+
anchors.bottomMargin: Theme.spacing.rowPaddingY
|
|
611
|
+
Column {
|
|
612
|
+
id: peers
|
|
613
|
+
width: parent.width
|
|
614
|
+
|
|
615
|
+
Repeater {
|
|
616
|
+
id: subRows
|
|
617
|
+
model: root.heldRows
|
|
618
|
+
delegate: Flea.MenuRow {
|
|
619
|
+
id: subRow
|
|
620
|
+
required property var modelData
|
|
621
|
+
required property int index
|
|
622
|
+
width: peers.width
|
|
623
|
+
// Which mark a whole flyout draws is ui/js/Menu.js submenuGlyph's to say, so the
|
|
624
|
+
// read-back submenuGlyphs() above and the drawn row cannot answer differently.
|
|
625
|
+
// A flyout row may carry its own mark and caption: OpenWith.html rides each
|
|
626
|
+
// application's own Icon in the mark slot and puts "default" in the hint slot,
|
|
627
|
+
// and its tail row sits under a separator. MenuAdditions040 leaves carry a
|
|
628
|
+
// keyHint letter instead, drawn only while key hints are on, like every hint.
|
|
629
|
+
entry: ({ label: subRow.modelData.label, action: "",
|
|
630
|
+
disabled: subRow.modelData.disabled === true,
|
|
631
|
+
separator: subRow.modelData.separator === true,
|
|
632
|
+
hint: subRow.modelData.hint !== undefined ? subRow.modelData.hint
|
|
633
|
+
: subRow.modelData.keyHint !== undefined && ViewState.keyHints
|
|
634
|
+
? subRow.modelData.keyHint : undefined,
|
|
635
|
+
// flea-qml: the leaf's letter, bold in its label while key hints are on.
|
|
636
|
+
mnemonic: subRow.modelData.keyHint !== undefined && ViewState.keyHints
|
|
637
|
+
? (subRow.modelData.mark !== undefined ? subRow.modelData.mark : subRow.modelData.keyHint) : undefined,
|
|
638
|
+
icon: subRow.modelData.icon,
|
|
639
|
+
tagRow: subRow.modelData.tagRow,
|
|
640
|
+
glyph: subRow.modelData.glyph !== undefined ? subRow.modelData.glyph
|
|
641
|
+
: Menu.submenuGlyph(root.heldAction) })
|
|
642
|
+
current: root.submenuCursor === subRow.index
|
|
643
|
+
onPressedChanged: MenuRefresh.pressChanged(root, subRow.pressed)
|
|
644
|
+
// A flyout opened by key can land under the resting pointer too, so it reads the same point.
|
|
645
|
+
lastPointerGlobal: root.pointerGlobal
|
|
646
|
+
onPointerSeen: function (at) { root.pointerGlobal = at }
|
|
647
|
+
onPointerMoved: if (!root.pointerSettling && subRow.modelData.separator !== true) root.submenuCursor = subRow.index
|
|
648
|
+
onActivated: root.chooseSub(subRow.modelData.id)
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
Flea.MenuEdgeFade {
|
|
654
|
+
anchors.top: parent.top
|
|
655
|
+
inset: Theme.spacing.rowPaddingY
|
|
656
|
+
reach: root.fadeReach
|
|
657
|
+
visible: subScroll.contentY > 0
|
|
658
|
+
}
|
|
659
|
+
Flea.MenuEdgeFade {
|
|
660
|
+
anchors.bottom: parent.bottom
|
|
661
|
+
inset: Theme.spacing.rowPaddingY
|
|
662
|
+
reach: root.fadeReach
|
|
663
|
+
visible: subScroll.contentY + subScroll.height < subScroll.contentHeight
|
|
664
|
+
rotation: 180
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// One focus catcher for the whole menu: real QML focus never moves into the Repeater rows
|
|
669
|
+
// themselves, so every key lands here regardless of which level is open. They arrive through
|
|
670
|
+
// keys.toml's own table, so j and k step this list the way they step every other one.
|
|
671
|
+
Item {
|
|
672
|
+
id: keyCatcher
|
|
673
|
+
anchors.fill: parent
|
|
674
|
+
focus: true
|
|
675
|
+
|
|
676
|
+
Keys.onPressed: function (event) {
|
|
677
|
+
var action = Keymap.lookup(event.key, event.text, event.modifiers, "menu")
|
|
678
|
+
event.accepted = true
|
|
679
|
+
if (action === "escape") {
|
|
680
|
+
if (root.submenuOpen) {
|
|
681
|
+
root.openSubmenuRow = -1
|
|
682
|
+
root.loneFlyoutAction = ""
|
|
683
|
+
} else
|
|
684
|
+
root.close()
|
|
685
|
+
event.accepted = true
|
|
686
|
+
return
|
|
687
|
+
}
|
|
688
|
+
if (action === "cursorDown") {
|
|
689
|
+
if (root.submenuOpen)
|
|
690
|
+
root.submenuCursor = root.stepSubmenu(root.submenuCursor, 1)
|
|
691
|
+
else
|
|
692
|
+
root.cursor = root.stepCursor(root.cursor, 1)
|
|
693
|
+
event.accepted = true
|
|
694
|
+
return
|
|
695
|
+
}
|
|
696
|
+
if (action === "cursorUp") {
|
|
697
|
+
if (root.submenuOpen)
|
|
698
|
+
root.submenuCursor = root.stepSubmenu(root.submenuCursor, -1)
|
|
699
|
+
else
|
|
700
|
+
root.cursor = root.stepCursor(root.cursor, -1)
|
|
701
|
+
event.accepted = true
|
|
702
|
+
return
|
|
703
|
+
}
|
|
704
|
+
if (action === "parent") {
|
|
705
|
+
root.openSubmenuRow = -1
|
|
706
|
+
root.loneFlyoutAction = ""
|
|
707
|
+
return
|
|
708
|
+
}
|
|
709
|
+
if (action === "menuRight") { root.openSubmenu(root.cursor); return }
|
|
710
|
+
// A flyout letter answers only the flyout it was opened for.
|
|
711
|
+
if (root.submenuOpen) {
|
|
712
|
+
var opener = root.loneFlyoutAction.length > 0
|
|
713
|
+
? { action: root.loneFlyoutAction } : root.entries[root.openSubmenuRow]
|
|
714
|
+
if (opener && (opener.action === "copyAs" || opener.action === "pasteAs")) {
|
|
715
|
+
var leaves = root.submenuEntries
|
|
716
|
+
for (var l = 0; l < leaves.length; l++) {
|
|
717
|
+
if (leaves[l].separator === true) continue
|
|
718
|
+
if (leaves[l].id === action) { root.chooseSub(leaves[l].id); return }
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
// 1 to 7 toggle the Tags flyout row that carries the digit, like a click.
|
|
722
|
+
if (opener && opener.action === "tags" && /^tag[1-7]$/.test(action)) { root.chooseSub(root.submenuEntries[Number(action.charAt(3)) - 1].id); return }
|
|
723
|
+
}
|
|
724
|
+
if (action === "open" || action === "preview") {
|
|
725
|
+
if (root.submenuOpen) {
|
|
726
|
+
var sub = root.submenuEntries[root.submenuCursor]
|
|
727
|
+
if (sub)
|
|
728
|
+
root.chooseSub(sub.id)
|
|
729
|
+
} else {
|
|
730
|
+
var entry = root.entries[root.cursor]
|
|
731
|
+
if (Menu.hasSubmenu(entry))
|
|
732
|
+
root.openSubmenu(root.cursor)
|
|
733
|
+
else if (entry && entry.separator !== true)
|
|
734
|
+
root.choose(entry.action)
|
|
735
|
+
}
|
|
736
|
+
event.accepted = true
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
onCompareKindsChanged: root.refreshProviderRows()
|
|
741
|
+
readonly property bool langMarks: ViewState.langMarks
|
|
742
|
+
onLangMarksChanged: root.refreshProviderRows()
|
|
743
|
+
}
|