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,482 @@
|
|
|
1
|
+
// Bound: the page Components below read this file's root and document, and are only built by its own Loaders and Repeater.
|
|
2
|
+
pragma ComponentBehavior: Bound
|
|
3
|
+
|
|
4
|
+
import QtQuick
|
|
5
|
+
import QtQuick.Pdf
|
|
6
|
+
import qs.Commons
|
|
7
|
+
import "js/Format.js" as Format
|
|
8
|
+
import "js/PreviewSettle.js" as PreviewSettle
|
|
9
|
+
import "js/PreviewSwap.js" as PreviewSwap
|
|
10
|
+
import "js/Swap.js" as Swap
|
|
11
|
+
|
|
12
|
+
// A PDF in the preview column's frame, or a page of it in Quick Look. QtPdf ships inside the already
|
|
13
|
+
// installed qt6-webengine and needs no package of its own; proven to import and render under
|
|
14
|
+
// Quickshell itself on this box, not only under qml6.
|
|
15
|
+
Item {
|
|
16
|
+
id: root
|
|
17
|
+
|
|
18
|
+
property string path: ""
|
|
19
|
+
property bool active: false
|
|
20
|
+
// The backend a slow document is fetched through, null where no fetch runs.
|
|
21
|
+
property var backend: null
|
|
22
|
+
// Which viewer this is, so the backend's copy cleanup never touches the other's.
|
|
23
|
+
property string viewerSlot: ""
|
|
24
|
+
// True on a storage class that can hang: the document loads from the fetched copy.
|
|
25
|
+
property bool fetchFirst: false
|
|
26
|
+
// The fetch in flight, the local copy it handed back, and what its failure says.
|
|
27
|
+
property int fetchId: 0
|
|
28
|
+
property string localCopy: ""
|
|
29
|
+
property string copyError: ""
|
|
30
|
+
// Decided once per opened document, so a later class change neither blanks nor reloads it.
|
|
31
|
+
property bool fetchedCopy: false
|
|
32
|
+
// The backend's flag for a fetch that never answered; any other copy failure could not be read.
|
|
33
|
+
property bool copyStalled: false
|
|
34
|
+
readonly property string failSentence: root.copyStalled ? "This file is not responding."
|
|
35
|
+
: "This file could not be read."
|
|
36
|
+
// Which page the frame is showing, zero-based, always inside the document it belongs to; the page under the frame's top when continuous.
|
|
37
|
+
property int page: 0
|
|
38
|
+
// The Flickable the page scrolls in, so the loading mark stands in the visible frame at any zoom.
|
|
39
|
+
property Item viewport: null
|
|
40
|
+
// The column's mode: every page at this item's width, one gap apart, inside the viewport; Quick Look shows one page.
|
|
41
|
+
property bool continuous: false
|
|
42
|
+
|
|
43
|
+
// What the facts table shows as Pages; 0 until the document is ready, or if it never becomes so.
|
|
44
|
+
readonly property int pageCount: doc.status === PdfDocument.Ready ? doc.pageCount : 0
|
|
45
|
+
// A render error fails the column only before its first draw and on the page under the frame's top; every other page error leaves only its own slot empty.
|
|
46
|
+
property bool pageFailed: false
|
|
47
|
+
readonly property bool failed: doc.status === PdfDocument.Error || root.copyError.length > 0 || root.pageFailed
|
|
48
|
+
|
|
49
|
+
// The page whose render is on screen, -1 until one has landed for this document.
|
|
50
|
+
property int shownPage: -1
|
|
51
|
+
// A render slower than the listing swap's cap stops passing the old page off as the one asked for.
|
|
52
|
+
property bool fellBack: false
|
|
53
|
+
// When the loading state went up, 0 while none stands; the page that replaces it waits behind it for Swap.MIN_SHOW_MS.
|
|
54
|
+
property double fellBackAt: 0
|
|
55
|
+
// What the chrome counts: the page on screen, or the one asked for once nothing else stands in for it.
|
|
56
|
+
readonly property int drawnPage: root.shownPage >= 0 && !root.fellBack ? root.shownPage : root.page
|
|
57
|
+
|
|
58
|
+
// The page's proportions come from the document, never from the rendered image. Reading the
|
|
59
|
+
// image's implicit size closed a loop through the width binding below: sourceSize changed the
|
|
60
|
+
// implicit size, which re-evaluated width, which re-set sourceSize. Qt broke that binding, and a
|
|
61
|
+
// broken width binding is a page that never resizes when the frame or the zoom changes.
|
|
62
|
+
// corner: a document mixing page shapes draws the old page in the new page's box until its render lands.
|
|
63
|
+
readonly property real pageAspect: {
|
|
64
|
+
if (root.continuous || doc.status !== PdfDocument.Ready || root.pageCount <= 0)
|
|
65
|
+
return 1
|
|
66
|
+
var box = doc.pagePointSize(Math.min(root.page, root.pageCount - 1))
|
|
67
|
+
return box.height > 0 ? box.width / box.height : 1
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Each page's height over its width, read from the document once when it becomes ready; the sizes read are counted for the tests.
|
|
71
|
+
property var pageRatios: []
|
|
72
|
+
property int sizeReads: 0
|
|
73
|
+
Connections {
|
|
74
|
+
target: doc
|
|
75
|
+
function onStatusChanged() {
|
|
76
|
+
var ratios = []
|
|
77
|
+
for (var i = 0; root.continuous && doc.status === PdfDocument.Ready && i < doc.pageCount; i++) {
|
|
78
|
+
var box = doc.pagePointSize(i)
|
|
79
|
+
ratios.push(box.width > 0 ? box.height / box.width : 0)
|
|
80
|
+
}
|
|
81
|
+
root.sizeReads += ratios.length
|
|
82
|
+
root.pageRatios = ratios
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Each page's top and height at this item's width, so the stack is as tall as it will be before any page renders.
|
|
86
|
+
readonly property var layout: {
|
|
87
|
+
var tops = [], heights = [], y = 0
|
|
88
|
+
for (var i = 0; root.width > 0 && i < root.pageRatios.length; i++) {
|
|
89
|
+
tops.push(y)
|
|
90
|
+
heights.push(Math.round(root.width * root.pageRatios[i]))
|
|
91
|
+
y += heights[i] + Theme.spacing.gap
|
|
92
|
+
}
|
|
93
|
+
return { tops: tops, heights: heights, height: Math.max(0, y - Theme.spacing.gap) }
|
|
94
|
+
}
|
|
95
|
+
readonly property real stackHeight: root.layout.height
|
|
96
|
+
readonly property real viewTop: root.viewport ? root.viewport.contentY : 0
|
|
97
|
+
readonly property real viewHeight: root.viewport ? root.viewport.height : 0
|
|
98
|
+
// Pages within half a frame of the frame hold an image; the others hold none.
|
|
99
|
+
readonly property int nearFirst: root.pageAt(root.viewTop - root.viewHeight / 2)
|
|
100
|
+
readonly property int nearLast: root.pageAt(root.viewTop + root.viewHeight * 1.5)
|
|
101
|
+
// The Qt render width in device pixels, held through small resizes so a drag does not render every pixel.
|
|
102
|
+
property int renderWidth: 0
|
|
103
|
+
onWidthChanged: root.fitRenderWidth()
|
|
104
|
+
onLayoutChanged: { root.pageFromOffset(); root.syncWindow() }
|
|
105
|
+
onNearFirstChanged: root.syncWindow()
|
|
106
|
+
onNearLastChanged: root.syncWindow()
|
|
107
|
+
onViewTopChanged: root.pageFromOffset()
|
|
108
|
+
|
|
109
|
+
// The page whose band, its height and the gap after it, holds the offset.
|
|
110
|
+
function pageAt(y) {
|
|
111
|
+
var tops = root.layout.tops
|
|
112
|
+
var lo = 0, hi = tops.length - 1
|
|
113
|
+
while (lo < hi) {
|
|
114
|
+
var mid = (lo + hi + 1) >> 1
|
|
115
|
+
if (tops[mid] <= y) lo = mid
|
|
116
|
+
else hi = mid - 1
|
|
117
|
+
}
|
|
118
|
+
return Math.max(0, lo)
|
|
119
|
+
}
|
|
120
|
+
function pageSlot(index) {
|
|
121
|
+
for (var i = 0; i < pages.count; i++)
|
|
122
|
+
if (pages.itemAt(i).pageNo === index) return pages.itemAt(i)
|
|
123
|
+
return null
|
|
124
|
+
}
|
|
125
|
+
function landedPages() {
|
|
126
|
+
var out = []
|
|
127
|
+
for (var i = 0; i < pages.count; i++)
|
|
128
|
+
if (pages.itemAt(i).landed) out.push(pages.itemAt(i).pageNo)
|
|
129
|
+
return out
|
|
130
|
+
}
|
|
131
|
+
// The slots are the pages of the near window and any page still rendering; a slot is added or dropped without moving the others.
|
|
132
|
+
function syncWindow() {
|
|
133
|
+
var last = Math.min(root.nearLast, root.layout.tops.length - 1)
|
|
134
|
+
var have = {}
|
|
135
|
+
for (var i = windowPages.count - 1; i >= 0; i--) {
|
|
136
|
+
var no = windowPages.get(i).pageNo
|
|
137
|
+
var busy = pages.itemAt(i) !== null && pages.itemAt(i).rendering
|
|
138
|
+
if (no > root.layout.tops.length - 1 || ((no < root.nearFirst || no > last) && !busy))
|
|
139
|
+
windowPages.remove(i)
|
|
140
|
+
else
|
|
141
|
+
have[no] = true
|
|
142
|
+
}
|
|
143
|
+
for (var n = root.nearFirst; n <= last; n++)
|
|
144
|
+
if (!have[n]) windowPages.append({ pageNo: n })
|
|
145
|
+
}
|
|
146
|
+
function pageFromOffset() { if (root.continuous && root.pageCount > 0) root.page = root.pageAt(root.viewTop) }
|
|
147
|
+
function fitRenderWidth() {
|
|
148
|
+
var target = Math.round(root.width * Screen.devicePixelRatio)
|
|
149
|
+
var ratio = root.renderWidth > 0 ? target / root.renderWidth : 0
|
|
150
|
+
if (target > 0 && (ratio > 1.1 || ratio < 0.9))
|
|
151
|
+
root.renderWidth = target
|
|
152
|
+
}
|
|
153
|
+
// The first frame holds when every page it shows has landed; later pages are never waited on, so a scroll never blanks the column.
|
|
154
|
+
function firstDrawn() {
|
|
155
|
+
if (!root.continuous || root.shownPage >= 0 || root.pageCount <= 0)
|
|
156
|
+
return
|
|
157
|
+
for (var i = root.pageAt(root.viewTop); i <= root.pageAt(root.viewTop + root.viewHeight); i++) {
|
|
158
|
+
var slot = root.pageSlot(i)
|
|
159
|
+
if (!slot || !slot.settled)
|
|
160
|
+
return
|
|
161
|
+
}
|
|
162
|
+
root.shownPage = root.pageAt(root.viewTop)
|
|
163
|
+
}
|
|
164
|
+
function renderBusy() {
|
|
165
|
+
if (!root.continuous)
|
|
166
|
+
return root.pageItem !== null && root.pageItem.status === Image.Loading
|
|
167
|
+
for (var i = 0; i < pages.count; i++)
|
|
168
|
+
if (pages.itemAt(i).rendering)
|
|
169
|
+
return true
|
|
170
|
+
return false
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// A new document starts at its first page; an idle press opens on the next frame, a walk or a render in flight waits for the settle.
|
|
174
|
+
onPathChanged: { root.page = 0; root.requestOpen() }
|
|
175
|
+
onOpenedChanged: root.fetchForOpened()
|
|
176
|
+
|
|
177
|
+
// A hangable document is fetched once per opening; anything else loads in place.
|
|
178
|
+
function fetchForOpened() {
|
|
179
|
+
root.localCopy = ""
|
|
180
|
+
root.copyError = ""
|
|
181
|
+
root.copyStalled = false
|
|
182
|
+
root.fetchedCopy = root.opened.length > 0 && root.fetchFirst === true && root.backend !== null
|
|
183
|
+
if (!root.fetchedCopy)
|
|
184
|
+
return
|
|
185
|
+
root.fetchId = root.backend.pdfCopy(root.opened, root.viewerSlot)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
Connections {
|
|
189
|
+
target: root.backend
|
|
190
|
+
function onPdfCopied(id, path, err, stalled) {
|
|
191
|
+
if (id !== root.fetchId || root.fetchedCopy !== true)
|
|
192
|
+
return
|
|
193
|
+
if (err.length > 0) {
|
|
194
|
+
root.copyError = err
|
|
195
|
+
root.copyStalled = stalled
|
|
196
|
+
} else {
|
|
197
|
+
root.localCopy = path
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// The copy, once it lands; in place while no fetch runs, and nothing while one is out.
|
|
203
|
+
function docSource() {
|
|
204
|
+
if (root.opened.length === 0)
|
|
205
|
+
return ""
|
|
206
|
+
if (root.fetchedCopy !== true)
|
|
207
|
+
return Format.fileUri(root.opened)
|
|
208
|
+
return root.localCopy.length > 0 ? Format.fileUri(root.localCopy) : ""
|
|
209
|
+
}
|
|
210
|
+
onPageCountChanged: if (root.pageCount > 0) root.page = Math.min(root.page, root.pageCount - 1)
|
|
211
|
+
// A turn arms the cap for a page other than the one on screen; with no page shown yet it does nothing, and turning back onto the shown page stops the cap instead.
|
|
212
|
+
onPageChanged: {
|
|
213
|
+
if (!root.pageItem || root.pageItem.status !== Image.Loading) return
|
|
214
|
+
if (root.shownPage < 0) return
|
|
215
|
+
if (root.page !== root.shownPage) renderCap.start()
|
|
216
|
+
else { renderCap.stop(); root.endFallBack() }
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// The loading state leaves once it has stood Swap.MIN_SHOW_MS; until then the page waits behind it.
|
|
220
|
+
function endFallBack() {
|
|
221
|
+
var left = root.fellBack ? Swap.showLeft(root.fellBackAt, Date.now()) : 0
|
|
222
|
+
if (left > 0) {
|
|
223
|
+
renderMin.interval = left
|
|
224
|
+
renderMin.restart()
|
|
225
|
+
return
|
|
226
|
+
}
|
|
227
|
+
renderMin.stop()
|
|
228
|
+
root.fellBack = false
|
|
229
|
+
root.fellBackAt = 0
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function turn(delta) {
|
|
233
|
+
if (root.pageCount <= 0)
|
|
234
|
+
return
|
|
235
|
+
var next = Math.max(0, Math.min(root.pageCount - 1, root.page + delta))
|
|
236
|
+
if (!root.continuous)
|
|
237
|
+
root.page = next
|
|
238
|
+
else if (root.viewport)
|
|
239
|
+
root.viewport.contentY = Math.max(0, Math.min(root.layout.tops[next], root.viewport.contentHeight - root.viewport.height))
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Loading a page other than the one on screen starts the cap; a landed or failed render ends it.
|
|
243
|
+
function renderChanged() {
|
|
244
|
+
var page = root.pageItem
|
|
245
|
+
if (page.status === Image.Loading) {
|
|
246
|
+
if (root.shownPage >= 0 && page.currentFrame !== root.shownPage) {
|
|
247
|
+
renderMin.stop()
|
|
248
|
+
renderCap.restart()
|
|
249
|
+
}
|
|
250
|
+
return
|
|
251
|
+
}
|
|
252
|
+
renderCap.stop()
|
|
253
|
+
root.endFallBack()
|
|
254
|
+
// A document switch reports Ready for loads that drew nothing, or that drew the last file.
|
|
255
|
+
var landed = page.status === Image.Ready && page.implicitWidth > 0
|
|
256
|
+
&& page.source.toString() === doc.source.toString()
|
|
257
|
+
root.shownPage = landed ? page.currentFrame : -1
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Issue 117, vianney-g: a source change while an async page render is in flight can destroy the
|
|
261
|
+
// carrier device under Qt's own reader thread, which aborts the process, so a walk through a
|
|
262
|
+
// folder of PDFs settles before a document is opened rather than opening one per cursor step.
|
|
263
|
+
property string opened: ""
|
|
264
|
+
readonly property int settleMs: PreviewSwap.DOCUMENT_SETTLE_MS
|
|
265
|
+
// The last path or active change, so an isolated press opens at once and a walk still settles.
|
|
266
|
+
property double lastRequestAt: 0
|
|
267
|
+
onActiveChanged: root.requestOpen()
|
|
268
|
+
|
|
269
|
+
// One opener for the timer and the idle fast path, so both switch the same way.
|
|
270
|
+
function openPending() {
|
|
271
|
+
var next = root.active ? root.path : ""
|
|
272
|
+
if (next === root.opened)
|
|
273
|
+
return
|
|
274
|
+
// Another document's page is never this one's: it is dropped, and kept by no render, before the switch.
|
|
275
|
+
renderCap.stop()
|
|
276
|
+
renderMin.stop()
|
|
277
|
+
root.fellBack = false
|
|
278
|
+
root.fellBackAt = 0
|
|
279
|
+
root.shownPage = -1
|
|
280
|
+
root.pageFailed = false
|
|
281
|
+
root.opened = next
|
|
282
|
+
if (root.continuous && root.viewport)
|
|
283
|
+
root.viewport.contentY = 0
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// An idle press opens on the next presented frame, so that frame shows the page Quick Look has; the settle is the backstop.
|
|
287
|
+
property bool fastArmed: false
|
|
288
|
+
// Opens taken by the fast path, so a test tells them from the settle by count, never by time.
|
|
289
|
+
property int fastOpens: 0
|
|
290
|
+
function runFast() {
|
|
291
|
+
if (!root.fastArmed)
|
|
292
|
+
return
|
|
293
|
+
root.fastArmed = false
|
|
294
|
+
pdfSettle.stop()
|
|
295
|
+
root.fastOpens += 1
|
|
296
|
+
root.openPending()
|
|
297
|
+
}
|
|
298
|
+
Connections {
|
|
299
|
+
target: root.fastArmed ? root.Window.window : null
|
|
300
|
+
function onFrameSwapped() { root.runFast() }
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// An idle press with no render in flight opens at once, and a change that opens nothing stamps nothing.
|
|
304
|
+
function requestOpen() {
|
|
305
|
+
if ((root.active ? root.path : "") === root.opened)
|
|
306
|
+
return
|
|
307
|
+
var now = Date.now()
|
|
308
|
+
root.fastArmed = PreviewSettle.pdfOpenNow(now, root.lastRequestAt, root.settleMs, root.renderBusy())
|
|
309
|
+
root.lastRequestAt = now
|
|
310
|
+
pdfSettle.restart()
|
|
311
|
+
}
|
|
312
|
+
Timer {
|
|
313
|
+
id: pdfSettle
|
|
314
|
+
interval: root.settleMs
|
|
315
|
+
onTriggered: { root.fastArmed = false; root.openPending() }
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// The cap draws the loading state by 100 ms, as the listing swap's does, and it then stands Swap.MIN_SHOW_MS.
|
|
319
|
+
Timer {
|
|
320
|
+
id: renderCap
|
|
321
|
+
objectName: "renderCap"
|
|
322
|
+
interval: Swap.CAP_MS
|
|
323
|
+
onTriggered: {
|
|
324
|
+
if (!root.fellBack)
|
|
325
|
+
root.fellBackAt = Date.now()
|
|
326
|
+
root.fellBack = true
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// The loading state has stood its minimum, so the page that landed meanwhile shows now.
|
|
331
|
+
Timer {
|
|
332
|
+
id: renderMin
|
|
333
|
+
objectName: "renderMin"
|
|
334
|
+
onTriggered: { root.fellBack = false; root.fellBackAt = 0 }
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
PdfDocument {
|
|
338
|
+
id: doc
|
|
339
|
+
// Format.fileUri, not a concatenation: a path can carry a # or a ? and either one truncates
|
|
340
|
+
// a hand-built URI at that character. A document is only opened while the column shows one.
|
|
341
|
+
source: root.docSource()
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Quick Look's one page: built only when this is not the column's stack, so the stack holds no image of its own besides its pages.
|
|
345
|
+
Loader {
|
|
346
|
+
id: single
|
|
347
|
+
anchors.fill: parent
|
|
348
|
+
active: !root.continuous
|
|
349
|
+
sourceComponent: singlePage
|
|
350
|
+
}
|
|
351
|
+
// The drawn page itself, for the geometry gate: sized to the contain of the viewport at the
|
|
352
|
+
// zoom, so its rect is the picture and not the frame it is centred in.
|
|
353
|
+
readonly property Item pageItem: single.item ? single.item.image : null
|
|
354
|
+
|
|
355
|
+
Component {
|
|
356
|
+
id: singlePage
|
|
357
|
+
|
|
358
|
+
Item {
|
|
359
|
+
readonly property Item image: page
|
|
360
|
+
|
|
361
|
+
// The page's own paper under the raster: on this box a rendered page can arrive with text drawn
|
|
362
|
+
// and no background, and the dark frame showed through it. Paper is the document's, not a theme
|
|
363
|
+
// role, so the colour is a constant; visible only with the page, so a loading document draws none.
|
|
364
|
+
Rectangle {
|
|
365
|
+
anchors.centerIn: parent
|
|
366
|
+
visible: page.visible
|
|
367
|
+
width: page.width
|
|
368
|
+
height: page.height
|
|
369
|
+
color: "#ffffff"
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// The page is the only light surface in the app, which is exactly what the canvas draws.
|
|
373
|
+
PdfPageImage {
|
|
374
|
+
id: page
|
|
375
|
+
anchors.centerIn: parent
|
|
376
|
+
// Drawn once a render has landed: the paper alone before it was the white flash on every turn.
|
|
377
|
+
visible: root.shownPage >= 0 && !root.fellBack
|
|
378
|
+
document: doc
|
|
379
|
+
// Qt ignores a frame at or past frameCount, which is 0 until the first render lands, so the binding reads it to reapply a turn made during that render.
|
|
380
|
+
currentFrame: page.frameCount > 0 ? Math.min(root.page, page.frameCount - 1) : 0
|
|
381
|
+
fillMode: Image.PreserveAspectFit
|
|
382
|
+
asynchronous: true
|
|
383
|
+
// Qt 6.8's double buffer: the page on screen stays until the next render is ready, where
|
|
384
|
+
// without it Qt dropped the old pixmap at the turn and the paper showed white for the render.
|
|
385
|
+
// Off until this document has a page on screen, so no render can keep another document's.
|
|
386
|
+
retainWhileLoading: root.shownPage >= 0
|
|
387
|
+
onStatusChanged: root.renderChanged()
|
|
388
|
+
// Fit inside the frame without ever upscaling past the page's own resolution.
|
|
389
|
+
width: Math.min(parent.width, parent.height * root.pageAspect)
|
|
390
|
+
height: Math.min(parent.height, parent.width / root.pageAspect)
|
|
391
|
+
|
|
392
|
+
// Rasterised at the size it is drawn at, so a zoomed page sharpens instead of scaling up a
|
|
393
|
+
// page-point-sized bitmap; the deadband and the assignment (not a binding) are both Qt's
|
|
394
|
+
// own PdfPageView.qml reRenderIfNecessary, without which a resize re-renders every frame.
|
|
395
|
+
onWidthChanged: page.rerenderIfNeeded()
|
|
396
|
+
// PdfPageImage copies the document's source into its own inherited source property only as
|
|
397
|
+
// the document turns Ready, and a re-render that beats that copy makes Qt warn that the two
|
|
398
|
+
// are in conflict; the guard below waits for the copy and this re-renders once it lands.
|
|
399
|
+
onSourceChanged: page.rerenderIfNeeded()
|
|
400
|
+
|
|
401
|
+
function rerenderIfNeeded() {
|
|
402
|
+
// source is a url, so it is converted before comparing: a bare === against a
|
|
403
|
+
// string is false forever and would stop this guard from ever firing. Opening the
|
|
404
|
+
// next document leaves the last one's source here until the copy, and the page box
|
|
405
|
+
// resizing meanwhile (pageAspect is 1 while it loads) was that warning, twice a switch.
|
|
406
|
+
if (page.source.toString() === "" || page.source.toString() !== doc.source.toString())
|
|
407
|
+
return
|
|
408
|
+
var target = Math.round(page.width)
|
|
409
|
+
if (target <= 0)
|
|
410
|
+
return
|
|
411
|
+
var ratio = page.sourceSize.width > 0 ? target / page.sourceSize.width : 0
|
|
412
|
+
if (ratio > 1.1 || ratio < 0.9)
|
|
413
|
+
page.sourceSize = Qt.size(target, 0)
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// The continuous stack: a slot per page of the near window, each holding an image while its page is near the frame or still rendering.
|
|
420
|
+
ListModel { id: windowPages }
|
|
421
|
+
Repeater {
|
|
422
|
+
id: pages
|
|
423
|
+
model: windowPages
|
|
424
|
+
delegate: Item {
|
|
425
|
+
id: slot
|
|
426
|
+
required property int pageNo
|
|
427
|
+
readonly property bool near: slot.pageNo >= root.nearFirst && slot.pageNo <= root.nearLast
|
|
428
|
+
readonly property bool landed: pageLoader.item !== null && pageLoader.item.landed
|
|
429
|
+
// A failed render counts as settled, so the first frame is never held for a page that will not come.
|
|
430
|
+
property bool errored: false
|
|
431
|
+
readonly property bool settled: slot.landed || slot.errored
|
|
432
|
+
// A page that left the frame keeps its image until the render in flight lands, so no render is cut off by its own page going away.
|
|
433
|
+
property bool rendering: false
|
|
434
|
+
y: root.layout.tops[slot.pageNo] || 0
|
|
435
|
+
width: root.width
|
|
436
|
+
height: root.layout.heights[slot.pageNo] || 0
|
|
437
|
+
onSettledChanged: root.firstDrawn()
|
|
438
|
+
onRenderingChanged: if (!slot.rendering) Qt.callLater(root.syncWindow)
|
|
439
|
+
|
|
440
|
+
function imageStatus(status) {
|
|
441
|
+
var drawn = root.shownPage >= 0
|
|
442
|
+
slot.rendering = status === Image.Loading
|
|
443
|
+
slot.errored = status === Image.Error
|
|
444
|
+
if (slot.errored && !drawn && slot.pageNo === root.pageAt(root.viewTop))
|
|
445
|
+
root.pageFailed = true
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
Loader {
|
|
449
|
+
id: pageLoader
|
|
450
|
+
anchors.fill: parent
|
|
451
|
+
active: slot.near || slot.rendering
|
|
452
|
+
sourceComponent: Item {
|
|
453
|
+
readonly property bool landed: image.status === Image.Ready && image.implicitWidth > 0
|
|
454
|
+
Rectangle {
|
|
455
|
+
anchors.fill: parent
|
|
456
|
+
visible: image.status === Image.Ready
|
|
457
|
+
color: "#ffffff"
|
|
458
|
+
}
|
|
459
|
+
PdfPageImage {
|
|
460
|
+
id: image
|
|
461
|
+
anchors.fill: parent
|
|
462
|
+
document: doc
|
|
463
|
+
currentFrame: slot.pageNo
|
|
464
|
+
fillMode: Image.Stretch
|
|
465
|
+
asynchronous: true
|
|
466
|
+
retainWhileLoading: true
|
|
467
|
+
sourceSize: Qt.size(root.renderWidth, 0)
|
|
468
|
+
onStatusChanged: slot.imageStatus(image.status)
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// Past the cap the loading mark takes the frame, the fallback ui/PaneSwap.qml gives a slow listing.
|
|
476
|
+
LoadingState {
|
|
477
|
+
parent: root.viewport ? root.viewport : root
|
|
478
|
+
anchors.fill: parent
|
|
479
|
+
visible: root.fellBack
|
|
480
|
+
heldOff: true
|
|
481
|
+
}
|
|
482
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import QtQuick
|
|
2
|
+
import "." as Flea
|
|
3
|
+
import "js/Scroll.js" as Scroll
|
|
4
|
+
|
|
5
|
+
// The column's scroll route and bounded session memory; no position is written to settings.
|
|
6
|
+
Item {
|
|
7
|
+
id: root
|
|
8
|
+
objectName: "previewScroll"
|
|
9
|
+
required property var column
|
|
10
|
+
parent: root.column.frameItem
|
|
11
|
+
anchors.fill: parent
|
|
12
|
+
|
|
13
|
+
readonly property var code: root.html && root.html.sourceView ? root.html.sourceCode : root.column.linesItem.code
|
|
14
|
+
readonly property var markdown: root.column.isMarkdownRow ? root.column.markdown : null
|
|
15
|
+
readonly property var html: root.column.isHtmlRow ? root.column.markdown : null
|
|
16
|
+
readonly property var viewport: root.column.linesItem.visible ? root.column.linesItem.viewport
|
|
17
|
+
: root.markdown ? root.markdown.viewport : root.html ? root.html.viewport : null
|
|
18
|
+
readonly property string subject: root.column.row && root.column.path.length > 0
|
|
19
|
+
? JSON.stringify([root.column.path, root.column.row.s, root.column.row.m]) : ""
|
|
20
|
+
readonly property bool contentReady: root.html ? root.html.contentReady : root.markdown ? root.markdown.contentReady : !!root.code && root.code.settled
|
|
21
|
+
readonly property bool loading: root.scrollPending || (root.column.isDocumentRow ? !root.column.markdown || root.column.markdown.loading || (root.contentReady && root.pendingRestore)
|
|
22
|
+
: root.column.linesItem.loading || (!!root.code && root.code.settled && (!root.code.firstScreen || root.pendingRestore))
|
|
23
|
+
)
|
|
24
|
+
property var places: ({})
|
|
25
|
+
property var order: []
|
|
26
|
+
readonly property int capacity: 256
|
|
27
|
+
property string identity: ""
|
|
28
|
+
property string filePath: ""
|
|
29
|
+
property var wanted: ({ y: 0 })
|
|
30
|
+
property bool pendingRestore: false
|
|
31
|
+
property bool applying: false
|
|
32
|
+
property string scrollKey: ""
|
|
33
|
+
readonly property bool scrollPending: root.scrollKey.length > 0 && !!root.column.swap
|
|
34
|
+
&& root.column.swap.capturing && root.column.swap.key === root.scrollKey
|
|
35
|
+
property real drawnY: 0
|
|
36
|
+
|
|
37
|
+
function store(path, fingerprint, place) {
|
|
38
|
+
var at = root.order.indexOf(path)
|
|
39
|
+
if (at >= 0) root.order.splice(at, 1)
|
|
40
|
+
root.order.push(path)
|
|
41
|
+
root.places[path] = { fingerprint: fingerprint, place: place }
|
|
42
|
+
while (root.order.length > root.capacity)
|
|
43
|
+
delete root.places[root.order.shift()]
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function remember() {
|
|
47
|
+
var v = root.viewport
|
|
48
|
+
if (!v || root.applying || root.pendingRestore || !root.contentReady
|
|
49
|
+
|| !root.identity || !root.column.row || root.column.path !== root.filePath
|
|
50
|
+
|| root.identity !== JSON.stringify([root.column.path, root.column.row.s, root.column.row.m]))
|
|
51
|
+
return
|
|
52
|
+
var place = { y: v.contentY - Scroll.limitsY(v).min }
|
|
53
|
+
if (root.markdown) {
|
|
54
|
+
var item = root.markdown.topBlockItem()
|
|
55
|
+
place.index = item ? item.blockIndex : -1
|
|
56
|
+
place.offset = item ? v.contentY - item.y : 0
|
|
57
|
+
}
|
|
58
|
+
root.store(root.filePath, root.identity, place)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function follow() {
|
|
62
|
+
root.pendingRestore = root.subject.length > 0
|
|
63
|
+
root.scrollKey = ""
|
|
64
|
+
root.identity = root.subject
|
|
65
|
+
root.filePath = root.identity ? root.column.path : ""
|
|
66
|
+
var saved = root.places[root.filePath]
|
|
67
|
+
root.wanted = saved && saved.fingerprint === root.identity ? saved.place : { y: 0 }
|
|
68
|
+
Qt.callLater(root.restore)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Layout and the saved place land before the preview hold releases its first live frame.
|
|
72
|
+
function restore() {
|
|
73
|
+
var v = root.viewport
|
|
74
|
+
if (!root.pendingRestore || root.applying || !v || !root.contentReady)
|
|
75
|
+
return
|
|
76
|
+
root.applying = true
|
|
77
|
+
v.forceLayout()
|
|
78
|
+
if (root.markdown && root.wanted.index !== undefined) {
|
|
79
|
+
root.markdown.savedY = Scroll.limitsY(v).min + root.wanted.y
|
|
80
|
+
root.markdown.savedIndex = root.wanted.index
|
|
81
|
+
root.markdown.savedOffset = root.wanted.offset
|
|
82
|
+
root.markdown.keepScroll = true
|
|
83
|
+
root.markdown.restoreScroll()
|
|
84
|
+
} else {
|
|
85
|
+
var bounds = Scroll.limitsY(v)
|
|
86
|
+
v.currentIndex = -1
|
|
87
|
+
v.contentY = Math.max(bounds.min, Math.min(bounds.max, bounds.min + root.wanted.y))
|
|
88
|
+
}
|
|
89
|
+
v.forceLayout()
|
|
90
|
+
if (!root.markdown && !(root.html && !root.html.sourceView) && (!root.code || !root.code.firstScreen)) {
|
|
91
|
+
root.applying = false
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
root.pendingRestore = false
|
|
95
|
+
root.applying = false
|
|
96
|
+
root.drawnY = v.contentY
|
|
97
|
+
root.remember()
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// A cold code window moves under the existing preview hold, so no frame draws missing lines.
|
|
101
|
+
function moved() {
|
|
102
|
+
var v = root.viewport
|
|
103
|
+
if (!v || root.applying || root.pendingRestore || !root.contentReady)
|
|
104
|
+
return
|
|
105
|
+
root.applying = true
|
|
106
|
+
v.forceLayout()
|
|
107
|
+
root.applying = false
|
|
108
|
+
if (!root.markdown && !(root.html && !root.html.sourceView) && root.code && !root.code.firstScreen && root.column.swap
|
|
109
|
+
&& !root.column.swap.holding && !root.column.swap.capturing) {
|
|
110
|
+
var target = v.contentY
|
|
111
|
+
var identity = root.identity
|
|
112
|
+
var key = "scroll:" + identity
|
|
113
|
+
root.scrollKey = key
|
|
114
|
+
root.applying = true
|
|
115
|
+
v.contentY = root.drawnY
|
|
116
|
+
root.applying = false
|
|
117
|
+
root.column.swap.hold(function () {
|
|
118
|
+
if (root.scrollKey !== key) return
|
|
119
|
+
if (root.identity === identity) {
|
|
120
|
+
root.applying = true
|
|
121
|
+
v.contentY = target
|
|
122
|
+
v.forceLayout()
|
|
123
|
+
root.applying = false
|
|
124
|
+
root.remember()
|
|
125
|
+
root.column.swap.start(false)
|
|
126
|
+
}
|
|
127
|
+
root.scrollKey = ""
|
|
128
|
+
}, key, true)
|
|
129
|
+
return
|
|
130
|
+
}
|
|
131
|
+
if (root.markdown || (root.html && !root.html.sourceView) || (root.code && root.code.firstScreen))
|
|
132
|
+
root.drawnY = v.contentY
|
|
133
|
+
root.remember()
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function pageBy(direction) {
|
|
137
|
+
var v = root.viewport
|
|
138
|
+
if (!v || !root.column.visible || root.column.overlayOpen || root.column.manualHold
|
|
139
|
+
|| root.column.pending || root.column.selectionCount > 1 || root.pendingRestore || root.scrollPending)
|
|
140
|
+
return
|
|
141
|
+
var bounds = Scroll.limitsY(v)
|
|
142
|
+
v.cancelFlick()
|
|
143
|
+
Scroll.stopTail(v)
|
|
144
|
+
v.contentY = Math.max(bounds.min, Math.min(bounds.max, v.contentY + direction * v.height))
|
|
145
|
+
v.forceLayout()
|
|
146
|
+
root.remember()
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function scrollPage(direction, viewport) {
|
|
150
|
+
viewport.contentY = Math.max(0, Math.min(viewport.contentHeight - viewport.height,
|
|
151
|
+
viewport.contentY + direction * Flea.Theme.rowHeight))
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
onSubjectChanged: root.follow()
|
|
155
|
+
onContentReadyChanged: Qt.callLater(root.restore)
|
|
156
|
+
onViewportChanged: {
|
|
157
|
+
if (root.viewport) bars.targetView = root.viewport
|
|
158
|
+
Qt.callLater(root.restore)
|
|
159
|
+
}
|
|
160
|
+
Connections {
|
|
161
|
+
target: root.code
|
|
162
|
+
function onFirstScreenChanged() {
|
|
163
|
+
if (root.pendingRestore) Qt.callLater(root.restore)
|
|
164
|
+
if (root.code.firstScreen && root.viewport && !root.pendingRestore)
|
|
165
|
+
root.drawnY = root.viewport.contentY
|
|
166
|
+
else
|
|
167
|
+
root.moved()
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
Connections {
|
|
171
|
+
target: root.viewport
|
|
172
|
+
// ListView has count; the rendered page's Flickable supplies only geometry and scrolling signals.
|
|
173
|
+
ignoreUnknownSignals: true
|
|
174
|
+
function onCountChanged() { Qt.callLater(root.restore) }
|
|
175
|
+
function onContentHeightChanged() { Qt.callLater(root.restore) }
|
|
176
|
+
function onOriginYChanged() { Qt.callLater(root.restore) }
|
|
177
|
+
function onContentYChanged() { root.moved() }
|
|
178
|
+
}
|
|
179
|
+
Flea.FastScrollHandler {
|
|
180
|
+
id: wheel
|
|
181
|
+
flickable: root.html ? root.viewport : root.column.linesItem.viewport
|
|
182
|
+
visible: (root.html !== null || root.column.linesItem.visible) && flickable !== null
|
|
183
|
+
onWheel: function (event) {
|
|
184
|
+
if (root.scrollPending) {
|
|
185
|
+
event.accepted = true
|
|
186
|
+
return
|
|
187
|
+
}
|
|
188
|
+
// This handler replaces FastScrollHandler.onWheel; explicitly run
|
|
189
|
+
// its shared scrolling logic once the preview handoff is complete.
|
|
190
|
+
wheel.wheeled()
|
|
191
|
+
wheel.handleWheel(event)
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
Loader {
|
|
195
|
+
id: bars
|
|
196
|
+
anchors.fill: parent
|
|
197
|
+
property var targetView: null
|
|
198
|
+
active: root.viewport !== null && targetView !== null
|
|
199
|
+
sourceComponent: Flea.ViewportScrollBars { flickable: bars.targetView }
|
|
200
|
+
}
|
|
201
|
+
}
|