buninu-browser 0.3.0 → 0.5.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/LICENSES/jsmdcui.txt +22 -0
- package/README.md +40 -4
- package/frontends/wayland/LICENSE-land +21 -0
- package/frontends/wayland/README.md +152 -0
- package/frontends/wayland/casty/LICENSE +21 -0
- package/frontends/wayland/casty/bookmarks.js +32 -0
- package/frontends/wayland/casty/click.js +96 -0
- package/frontends/wayland/casty/commands.js +61 -0
- package/frontends/wayland/casty/config.js +45 -0
- package/frontends/wayland/casty/download-directory.js +28 -0
- package/frontends/wayland/casty/download.js +49 -0
- package/frontends/wayland/casty/hints.js +334 -0
- package/frontends/wayland/casty/keys.js +56 -0
- package/frontends/wayland/casty/page-commands.js +80 -0
- package/frontends/wayland/casty/prompt-width.js +148 -0
- package/frontends/wayland/casty/urlbar.js +606 -0
- package/frontends/wayland/client.js +88 -0
- package/frontends/wayland/clipboard.js +80 -0
- package/frontends/wayland/index.js +130 -0
- package/frontends/wayland/input.js +75 -0
- package/frontends/wayland/protocol.js +55 -0
- package/frontends/wayland/protocols/wayland.xml +3248 -0
- package/frontends/wayland/protocols/xdg-shell.xml +1415 -0
- package/frontends/wayland/transport.js +120 -0
- package/frontends/wayland/urlbar.js +162 -0
- package/index.js +28 -1
- package/lib/audio/shared-connection.js +31 -0
- package/lib/cdp-server.js +15 -2
- package/lib/clipboard-command.js +10 -0
- package/lib/clipboard-powershell.js +22 -0
- package/lib/clipboard.js +37 -2
- package/lib/document-types.js +11 -0
- package/lib/headless-shell.js +54 -12
- package/lib/layout/text-layout.js +17 -9
- package/lib/paint/display-list.js +6 -1
- package/lib/qml/README.md +1427 -0
- package/lib/qml/builtins.js +771 -0
- package/lib/qml/canvas-dom.js +115 -0
- package/lib/qml/canvas.js +76 -0
- package/lib/qml/document.js +1199 -0
- package/lib/qml/fonts.js +69 -0
- package/lib/qml/format.js +9 -0
- package/lib/qml/host.js +352 -0
- package/lib/qml/images.js +199 -0
- package/lib/qml/launcher.js +132 -0
- package/lib/qml/loader.js +521 -0
- package/lib/qml/media-renderer.js +49 -0
- package/lib/qml/media.js +86 -0
- package/lib/qml/models.js +622 -0
- package/lib/qml/parser.js +381 -0
- package/lib/qml/qs +5 -0
- package/lib/qml/qscasty +3 -0
- package/lib/qml/qsheadless +3 -0
- package/lib/qml/qswayland +3 -0
- package/lib/qml/reactive.js +182 -0
- package/lib/qml/runtime.js +3603 -0
- package/lib/qml/shader/fragment.js +83 -0
- package/lib/qml/shader/qsb.js +27 -0
- package/lib/qml/shader/renderer.js +39 -0
- package/lib/qml/shader/runtime.js +61 -0
- package/lib/qml/shapes.js +251 -0
- package/lib/qml/shortcuts.js +65 -0
- package/lib/qml/text.js +109 -0
- package/lib/qml/textures.js +126 -0
- package/lib/qml/wayland-clipboard.js +32 -0
- package/lib/qml/window-constraints.js +16 -0
- package/lib/qml/worker-thread.js +70 -0
- package/lib/render-tree/index.js +16 -1
- package/lib/renderer/bindings.js +16 -1
- package/lib/renderer/canvas-2d.js +29 -0
- package/lib/renderer/document-selection.js +19 -0
- package/lib/renderer/host.js +45 -17
- package/lib/renderer/main.js +21 -6
- package/lib/renderer/page-realm.js +20 -10
- package/lib/renderer/page-renderer.js +497 -42
- package/lib/renderer/pointer-move.js +5 -3
- package/lib/renderer/render-interval.js +9 -0
- package/lib/renderer/text-input-paint.js +54 -0
- package/lib/renderer/text-input.js +57 -0
- package/lib/style/computed-style.js +10 -4
- package/package.json +1 -1
- package/test/audio-connection-lifetime.test.js +46 -0
- package/test/canvas-paint.test.js +8 -0
- package/test/clipboard.test.js +19 -0
- package/test/computed-style.test.js +12 -0
- package/test/document-selection.test.js +27 -0
- package/test/double-click.test.js +85 -0
- package/test/fixtures/canvas-damage.js +40 -0
- package/test/fixtures/fake-renderer.js +1 -0
- package/test/fixtures/flea-helpers/Dockerfile +36 -0
- package/test/fixtures/flea-helpers/bat.mjs +43 -0
- package/test/fixtures/flea-helpers/bin/bat +3 -0
- package/test/fixtures/flea-helpers/bin/bwrap +10 -0
- package/test/fixtures/flea-helpers/bin/bwrap-real-filter +9 -0
- package/test/fixtures/flea-helpers/bin/glow +3 -0
- package/test/fixtures/flea-helpers/bin/qs +3 -0
- package/test/fixtures/flea-helpers/bin/unsupported +3 -0
- package/test/fixtures/flea-helpers/check-highlighting.mjs +47 -0
- package/test/fixtures/flea-helpers/check-media.mjs +29 -0
- package/test/fixtures/flea-helpers/check-preview.mjs +27 -0
- package/test/fixtures/flea-helpers/check.mjs +36 -0
- package/test/fixtures/flea-helpers/highlight-cases.json +227 -0
- package/test/fixtures/flea-helpers/source-mime.xml +28 -0
- package/test/fixtures/flea-helpers/syntax-compat.mjs +23 -0
- package/test/fixtures/flea-thumbnail-stub/flea-placeholder.thumbnailer +4 -0
- package/test/fixtures/flea-thumbnail-stub/flea-thumbnail-stub +3 -0
- package/test/fixtures/omastorm-helpers/Dockerfile +35 -0
- package/test/fixtures/omastorm-helpers/check.mjs +56 -0
- package/test/fixtures/omastorm-helpers/launch.mjs +24 -0
- package/test/fixtures/omastorm-helpers/prepare.mjs +17 -0
- package/test/fixtures/omastorm-helpers/runtime.mjs +32 -0
- package/test/fixtures/pointer-paint-batching.js +23 -0
- package/test/fixtures/qml/flea/EscapeHint.qml +11 -0
- package/test/fixtures/qml/flea/LICENSE +21 -0
- package/test/fixtures/qml/flea/README.md +25 -0
- package/test/fixtures/qml/flea/Theme.qml +8 -0
- package/test/fixtures/qml/flea/demo.qml +24 -0
- package/test/fixtures/qml/flea/qmldir +3 -0
- package/test/fixtures/qml/flea-theme/LICENSE-Flea +21 -0
- package/test/fixtures/qml/flea-theme/LICENSE-Omarchy +20 -0
- package/test/fixtures/qml/flea-theme/README.md +70 -0
- package/test/fixtures/qml/flea-theme/button.qml +17 -0
- package/test/fixtures/qml/flea-theme/demo.qml +27 -0
- package/test/fixtures/qml/flea-theme/field.qml +21 -0
- package/test/fixtures/qml/flea-theme/imports/qs/Commons/BorderGeometry.js +373 -0
- package/test/fixtures/qml/flea-theme/imports/qs/Commons/Color.qml +258 -0
- package/test/fixtures/qml/flea-theme/imports/qs/Commons/I18n.qml +118 -0
- package/test/fixtures/qml/flea-theme/imports/qs/Commons/Numbers.js +19 -0
- package/test/fixtures/qml/flea-theme/imports/qs/Commons/Plural.js +91 -0
- package/test/fixtures/qml/flea-theme/imports/qs/Commons/Style.qml +561 -0
- package/test/fixtures/qml/flea-theme/imports/qs/Commons/Util.qml +188 -0
- package/test/fixtures/qml/flea-theme/imports/qs/Commons/qmldir +13 -0
- package/test/fixtures/qml/flea-theme/segment.qml +17 -0
- package/test/fixtures/qml/flea-theme/settings.qml +58 -0
- package/test/fixtures/qml/flea-theme/text-metrics.qml +10 -0
- package/test/fixtures/qml/flea-theme/ui/DialogButton.qml +150 -0
- package/test/fixtures/qml/flea-theme/ui/DialogField.qml +147 -0
- package/test/fixtures/qml/flea-theme/ui/EscapeHint.qml +11 -0
- package/test/fixtures/qml/flea-theme/ui/Glass.qml +114 -0
- package/test/fixtures/qml/flea-theme/ui/Glyph.qml +54 -0
- package/test/fixtures/qml/flea-theme/ui/GlyphSolid.qml +22 -0
- package/test/fixtures/qml/flea-theme/ui/Reveal.qml +54 -0
- package/test/fixtures/qml/flea-theme/ui/SettingsRuler.qml +85 -0
- package/test/fixtures/qml/flea-theme/ui/SettingsSegment.qml +85 -0
- package/test/fixtures/qml/flea-theme/ui/StableModel.qml +89 -0
- package/test/fixtures/qml/flea-theme/ui/Theme.qml +460 -0
- package/test/fixtures/qml/flea-theme/ui/ThemeColors.qml +43 -0
- package/test/fixtures/qml/flea-theme/ui/ViewState.qml +565 -0
- package/test/fixtures/qml/flea-theme/ui/js/Anchor.js +379 -0
- package/test/fixtures/qml/flea-theme/ui/js/AnchorHold.js +162 -0
- package/test/fixtures/qml/flea-theme/ui/js/Archive.js +157 -0
- package/test/fixtures/qml/flea-theme/ui/js/BackReturn.js +110 -0
- package/test/fixtures/qml/flea-theme/ui/js/Buttons.js +54 -0
- package/test/fixtures/qml/flea-theme/ui/js/ColumnMenu.js +111 -0
- package/test/fixtures/qml/flea-theme/ui/js/Columns.js +298 -0
- package/test/fixtures/qml/flea-theme/ui/js/Contrast.js +157 -0
- package/test/fixtures/qml/flea-theme/ui/js/Density.js +44 -0
- package/test/fixtures/qml/flea-theme/ui/js/DirSizes.js +129 -0
- package/test/fixtures/qml/flea-theme/ui/js/ExtThumbs.js +115 -0
- package/test/fixtures/qml/flea-theme/ui/js/Filter.js +284 -0
- package/test/fixtures/qml/flea-theme/ui/js/FolderSorts.js +108 -0
- package/test/fixtures/qml/flea-theme/ui/js/Format.js +305 -0
- package/test/fixtures/qml/flea-theme/ui/js/Icons.js +206 -0
- package/test/fixtures/qml/flea-theme/ui/js/Input.js +39 -0
- package/test/fixtures/qml/flea-theme/ui/js/KeyName.js +64 -0
- package/test/fixtures/qml/flea-theme/ui/js/Keymap.js +370 -0
- package/test/fixtures/qml/flea-theme/ui/js/Kinds.js +145 -0
- package/test/fixtures/qml/flea-theme/ui/js/Lists.js +11 -0
- package/test/fixtures/qml/flea-theme/ui/js/MakeDefault.js +186 -0
- package/test/fixtures/qml/flea-theme/ui/js/Match.js +27 -0
- package/test/fixtures/qml/flea-theme/ui/js/Material.js +109 -0
- package/test/fixtures/qml/flea-theme/ui/js/Menu.js +513 -0
- package/test/fixtures/qml/flea-theme/ui/js/Motion.js +16 -0
- package/test/fixtures/qml/flea-theme/ui/js/Mounts.js +320 -0
- package/test/fixtures/qml/flea-theme/ui/js/MouseNav.js +13 -0
- package/test/fixtures/qml/flea-theme/ui/js/Nav.js +328 -0
- package/test/fixtures/qml/flea-theme/ui/js/Palette.js +33 -0
- package/test/fixtures/qml/flea-theme/ui/js/Places.js +236 -0
- package/test/fixtures/qml/flea-theme/ui/js/Protocols.js +296 -0
- package/test/fixtures/qml/flea-theme/ui/js/RecentMode.js +154 -0
- package/test/fixtures/qml/flea-theme/ui/js/Search.js +396 -0
- package/test/fixtures/qml/flea-theme/ui/js/Settings.js +476 -0
- package/test/fixtures/qml/flea-theme/ui/js/SettingsAbout.js +99 -0
- package/test/fixtures/qml/flea-theme/ui/js/SettingsShelf.js +52 -0
- package/test/fixtures/qml/flea-theme/ui/js/Sort.js +127 -0
- package/test/fixtures/qml/flea-theme/ui/js/StateWords.js +42 -0
- package/test/fixtures/qml/flea-theme/ui/js/Swap.js +166 -0
- package/test/fixtures/qml/flea-theme/ui/js/TextSize.js +107 -0
- package/test/fixtures/qml/flea-theme/ui/js/Thumbs.js +158 -0
- package/test/fixtures/qml/flea-theme/ui/js/UiState.js +438 -0
- package/test/fixtures/qml/flea-theme/ui/js/Update.js +132 -0
- package/test/fixtures/qml/flea-theme/ui/js/UserDirs.js +56 -0
- package/test/fixtures/qml/flea-theme/ui/qmldir +227 -0
- package/test/fixtures/qml/hello.qml +26 -0
- package/test/fixtures/qml/imports/Demo/Toolkit/VersionLabel.qml +2 -0
- package/test/fixtures/qml/imports/Demo/Toolkit/VersionLabelNew.qml +2 -0
- package/test/fixtures/qml/imports/Demo/Toolkit/qmldir +3 -0
- package/test/fixtures/qml/imports/components/Badge.qml +15 -0
- package/test/fixtures/qml/imports/logic/base.js +2 -0
- package/test/fixtures/qml/imports/logic/counter.js +4 -0
- package/test/fixtures/qml/imports/logic/math.js +3 -0
- package/test/fixtures/qml/imports/logic/shared.js +3 -0
- package/test/fixtures/qml/imports/main.qml +21 -0
- package/test/fixtures/qml/imports/theme/Theme.qml +8 -0
- package/test/fixtures/qml/imports/theme/qmldir +2 -0
- package/test/fixtures/qml/multiply.qml +61 -0
- package/test/fixtures/qml-canvas-dom.js +90 -0
- package/test/fixtures/qml-fonts/main.qml +10 -0
- package/test/fixtures/qml-locale/check.mjs +6 -0
- package/test/fixtures/qml-locale/main.qml +8 -0
- package/test/fixtures/qml-media-audio.js +39 -0
- package/test/fixtures/qml-shader/grab.qml +14 -0
- package/test/fixtures/qml-shader/gradient.frag +5 -0
- package/test/fixtures/qml-shader/main.qml +14 -0
- package/test/fixtures/qml-shader/texture-grab.qml +25 -0
- package/test/fixtures/qml-shader/texture-size.frag +5 -0
- package/test/fixtures/qml-shader-check.mjs +24 -0
- package/test/fixtures/title-no-paint.js +20 -0
- package/test/helpers/flea-sandbox.js +48 -0
- package/test/helpers/quickshell-fixture.js +125 -0
- package/test/html-clipboard-wayland.test.js +47 -0
- package/test/index.test.js +13 -0
- package/test/manual-casty-without-qml.js +87 -0
- package/test/manual-double-click.html +21 -0
- package/test/manual-flea-application.js +49 -0
- package/test/manual-flea-binary.js +62 -0
- package/test/manual-flea-qml.js +9 -0
- package/test/manual-flea-settings.js +40 -0
- package/test/manual-flea-theme.js +40 -0
- package/test/manual-mouse-buttons.html +18 -0
- package/test/manual-omastorm-engine.mjs +19 -0
- package/test/manual-omastorm-shaders.mjs +28 -0
- package/test/manual-omastorm-software.mjs +25 -0
- package/test/manual-pointer-scroll.html +43 -0
- package/test/manual-qml-removal.js +46 -0
- package/test/manual-without-qml.js +45 -0
- package/test/pointer-drag.test.js +104 -0
- package/test/qml-canvas-dom.test.js +37 -0
- package/test/qml-canvas.test.js +21 -0
- package/test/qml-clipboard-bridge.test.js +25 -0
- package/test/qml-clipboard-wayland.test.js +40 -0
- package/test/qml-connections-timing.test.js +95 -0
- package/test/qml-controls-window.test.js +182 -0
- package/test/qml-dynamic.test.js +401 -0
- package/test/qml-flea-app.test.js +146 -0
- package/test/qml-flea-backend.test.js +78 -0
- package/test/qml-flea-columns-backend.test.js +38 -0
- package/test/qml-flea-compile.test.js +78 -0
- package/test/qml-flea-launcher.test.js +88 -0
- package/test/qml-flea-markdown-backend.test.js +31 -0
- package/test/qml-flea-media.test.js +28 -0
- package/test/qml-flea-navigation-backend.test.js +35 -0
- package/test/qml-flea-navigation-timing.test.js +147 -0
- package/test/qml-flea-preview-backend.test.js +53 -0
- package/test/qml-flea-previews.test.js +163 -0
- package/test/qml-flea-rows.test.js +101 -0
- package/test/qml-flea-textures.test.js +59 -0
- package/test/qml-flea-view-switch.test.js +33 -0
- package/test/qml-flea-wayland.test.js +68 -0
- package/test/qml-flea.test.js +34 -0
- package/test/qml-fonts.test.js +31 -0
- package/test/qml-grid-multiline.test.js +48 -0
- package/test/qml-host.test.js +238 -0
- package/test/qml-imports.test.js +102 -0
- package/test/qml-inherited-handlers.test.js +51 -0
- package/test/qml-input-selection.test.js +66 -0
- package/test/qml-interactions.test.js +309 -0
- package/test/qml-language.test.js +167 -0
- package/test/qml-launcher.test.js +54 -0
- package/test/qml-layout-text.test.js +205 -0
- package/test/qml-locale.test.js +45 -0
- package/test/qml-media.test.js +63 -0
- package/test/qml-nonvisual-visible.test.js +19 -0
- package/test/qml-persisted-delegates.test.js +45 -0
- package/test/qml-quickshell-controls.test.js +65 -0
- package/test/qml-quickshell-settings.test.js +62 -0
- package/test/qml-repeater.test.js +72 -0
- package/test/qml-shader-runtime.test.js +6 -0
- package/test/qml-shortcuts.test.js +39 -0
- package/test/qml-socket.test.js +60 -0
- package/test/qml-software-shader.test.js +55 -0
- package/test/qml-style-updates.test.js +124 -0
- package/test/qml-textures.test.js +66 -0
- package/test/qml-views.test.js +332 -0
- package/test/qml-window-update.test.js +36 -0
- package/test/qml-worker.test.js +69 -0
- package/test/qml.test.js +83 -0
- package/test/render-interval.test.js +33 -0
- package/test/renderer-host.test.js +11 -0
- package/test/text-input-pointer.test.js +31 -0
- package/test/text-input-scroll.test.js +29 -0
- package/test/text-input.test.js +47 -0
- package/test/title-no-paint.test.js +6 -0
- package/test/wayland-frontend.test.js +83 -0
- package/test/wayland-scroll.test.js +40 -0
- package/test/wayland-urlbar.test.js +61 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
pragma Singleton
|
|
2
|
+
import QtQuick
|
|
3
|
+
import Quickshell
|
|
4
|
+
import Quickshell.Io
|
|
5
|
+
import qs.Commons
|
|
6
|
+
import qs.Commons as Commons
|
|
7
|
+
import "js/Material.js" as Material
|
|
8
|
+
|
|
9
|
+
// shell.toml's [flea] background-alpha through Omarchy's reader, and Omarchy's Window Transparency mode: one plane per pixel, content opaque; AGENTS.md "Theme roles and sources".
|
|
10
|
+
QtObject {
|
|
11
|
+
id: root
|
|
12
|
+
|
|
13
|
+
readonly property string key: "flea.background-alpha"
|
|
14
|
+
// Pick candidate A: match Nautilus's 0.75 ground, lifting text rather than fading it like window opacity does.
|
|
15
|
+
property real glassAlpha: root.mode === "glassy" && root.usesDefault ? Material.floor(Theme.color.opaquePalette, Theme.textContrast) / 255 : 1
|
|
16
|
+
property bool focused: Qt.application.active
|
|
17
|
+
readonly property bool split: true
|
|
18
|
+
readonly property bool usesDefault: root.valueIn(Commons.Color.userShellValues) < 0 && root.valueIn(Commons.Color.themeShellValues) < 0
|
|
19
|
+
// "opaque", "glassy" or "transparent" (Omarchy's default), read from its toggle files by reread().
|
|
20
|
+
property string mode: "transparent"
|
|
21
|
+
property bool hasOpaque: false
|
|
22
|
+
property bool hasGlassy: false
|
|
23
|
+
// Set once by launch(), before the window exists, because a Wayland surface's format is fixed at creation.
|
|
24
|
+
property bool clear: false
|
|
25
|
+
// In whole 8-bit steps, so a value that rounds to 1 is 1; a launch a [flea] value pins opaque holds 1 until the next launch.
|
|
26
|
+
readonly property real alpha: root.clear ? root.stepped(root.wanted()) : 1
|
|
27
|
+
// False keeps every plane on its own opaque role, so a stock theme draws exactly what it drew before.
|
|
28
|
+
readonly property bool on: root.alpha < 1
|
|
29
|
+
readonly property color background: root.on ? Util.alpha(Theme.color.background, root.alpha) : Theme.color.background
|
|
30
|
+
readonly property color surface: root.on ? Util.alpha(Theme.color.surface, root.alpha) : Theme.color.surface
|
|
31
|
+
readonly property real listAlpha: root.on && root.usesDefault && root.mode === "glassy" && root.split ? Math.max(root.alpha, Material.listFloor(Theme.color.opaquePalette, Theme.textContrast) / 255) : root.alpha
|
|
32
|
+
readonly property color listBackground: root.on ? Util.alpha(Theme.color.background, root.listAlpha) : Theme.color.background
|
|
33
|
+
|
|
34
|
+
readonly property string toggleDir: (Quickshell.env("XDG_STATE_HOME") || Quickshell.env("HOME") + "/.local/state") + "/omarchy/toggles/hypr"
|
|
35
|
+
// A file test and not omarchy-hyprland-window-transparency, which needs OMARCHY_PATH that ssh and some launchers lack.
|
|
36
|
+
property FileView opaqueFile: FileView {
|
|
37
|
+
path: root.toggleDir + "/window-opaque.lua"
|
|
38
|
+
printErrors: false
|
|
39
|
+
onLoaded: root.hasOpaque = true
|
|
40
|
+
onLoadFailed: root.hasOpaque = false
|
|
41
|
+
}
|
|
42
|
+
property FileView glassyFile: FileView {
|
|
43
|
+
path: root.toggleDir + "/window-glassy.lua"
|
|
44
|
+
printErrors: false
|
|
45
|
+
onLoaded: root.hasGlassy = true
|
|
46
|
+
onLoadFailed: root.hasGlassy = false
|
|
47
|
+
}
|
|
48
|
+
// Hyprland reloads its config for a Window Transparency change, with no theme switch.
|
|
49
|
+
property Connections reloads: Connections {
|
|
50
|
+
target: Theme
|
|
51
|
+
function onConfigReloaded() { root.reread(); root.retag() }
|
|
52
|
+
function onFleaWindowOpened() { root.startTagger() }
|
|
53
|
+
}
|
|
54
|
+
// Only inside Hyprland, as ui/Theme.qml's event hookup: a headless run has no compositor to ask.
|
|
55
|
+
readonly property bool inHyprland: Quickshell.env("HYPRLAND_INSTANCE_SIGNATURE") !== null
|
|
56
|
+
// ui/GlassTagger.qml, made when Hyprland opens the first Flea window, so it costs nothing before the first rows.
|
|
57
|
+
property QtObject tagger: null
|
|
58
|
+
onModeChanged: root.retag()
|
|
59
|
+
onUsesDefaultChanged: root.retag()
|
|
60
|
+
|
|
61
|
+
// Sample input: 0.34 answers 87/255, 0.999 answers 1.
|
|
62
|
+
function stepped(value) { return Math.round(value * 255) / 255 }
|
|
63
|
+
|
|
64
|
+
// One shell.toml's value: -1 when it sets none, the clamped number, or 1 for what is not a number.
|
|
65
|
+
function valueIn(values) {
|
|
66
|
+
var v = values ? values[root.key] : undefined
|
|
67
|
+
if (typeof v !== "string" || v.length === 0) return -1
|
|
68
|
+
var n = Number(v)
|
|
69
|
+
return isFinite(n) ? Util.clampAlpha(n) : 1
|
|
70
|
+
}
|
|
71
|
+
// User and theme values keep their precedence; bare Transparent is opaque: no shipped theme sets an opacity of its own, and no toggle file means transparency was never chosen.
|
|
72
|
+
function wanted() {
|
|
73
|
+
var user = root.valueIn(Commons.Color.userShellValues)
|
|
74
|
+
if (user >= 0) return user
|
|
75
|
+
if (root.mode === "opaque") return 1
|
|
76
|
+
var theme = root.valueIn(Commons.Color.themeShellValues)
|
|
77
|
+
if (theme >= 0) return theme
|
|
78
|
+
return root.mode === "glassy" ? root.glassAlpha : 1
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function reread() {
|
|
82
|
+
root.opaqueFile.reload()
|
|
83
|
+
root.glassyFile.reload()
|
|
84
|
+
root.opaqueFile.waitForJob()
|
|
85
|
+
root.glassyFile.waitForJob()
|
|
86
|
+
root.mode = root.hasGlassy ? "glassy" : root.hasOpaque ? "opaque" : "transparent"
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// A [flea] value that pins 1 keeps an opaque surface; every other launch is made clear, so each Window Transparency switch shows live.
|
|
90
|
+
function pinsOpaque() {
|
|
91
|
+
var user = root.valueIn(Commons.Color.userShellValues)
|
|
92
|
+
if (user >= 0) return root.stepped(user) >= 1
|
|
93
|
+
var theme = root.valueIn(Commons.Color.themeShellValues)
|
|
94
|
+
return theme >= 0 && root.stepped(theme) >= 1
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Color's two shell readers load asynchronously; waiting here lands both before the decision.
|
|
98
|
+
function launch() {
|
|
99
|
+
Commons.Color.shellFile.waitForJob()
|
|
100
|
+
Commons.Color.userShellFile.waitForJob()
|
|
101
|
+
root.reread()
|
|
102
|
+
root.clear = !root.pinsOpaque()
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function startTagger() {
|
|
106
|
+
if (!root.inHyprland) return
|
|
107
|
+
if (!root.tagger) root.tagger = Qt.createComponent("GlassTagger.qml").createObject(root, {
|
|
108
|
+
mode: Qt.binding(function () { return root.mode }),
|
|
109
|
+
usesDefault: Qt.binding(function () { return root.usesDefault })
|
|
110
|
+
})
|
|
111
|
+
root.retag()
|
|
112
|
+
}
|
|
113
|
+
function retag() { if (root.tagger) root.tagger.retag() }
|
|
114
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import QtQuick
|
|
2
|
+
import QtQuick.Shapes
|
|
3
|
+
import qs.Commons
|
|
4
|
+
import "js/Icons.js" as Icons
|
|
5
|
+
|
|
6
|
+
// One row or sidebar mark, chosen by name. Lucide's grid is 24 units at stroke 2, scaled to the slot.
|
|
7
|
+
Item {
|
|
8
|
+
id: root
|
|
9
|
+
|
|
10
|
+
property string name: "file"
|
|
11
|
+
property color color: "transparent"
|
|
12
|
+
// Lucide draws on a 24 unit grid, so every path in Icons.js is in those units.
|
|
13
|
+
readonly property real grid: 24
|
|
14
|
+
// The mark's ceiling. Default is the row and menu mark; a surface drawing a mark alone passes its own.
|
|
15
|
+
property real maxSize: Theme.markSize
|
|
16
|
+
// The min() against the slot is the icon spec's own rule, so a smaller caller slot still wins
|
|
17
|
+
// (the Network "+" at the caption token needs it) and no container can ever enlarge a mark.
|
|
18
|
+
readonly property real markSize: Math.min(root.maxSize, root.width, root.height)
|
|
19
|
+
// Its own name: "scale" would shadow Item.scale, which qmllint flagged.
|
|
20
|
+
readonly property real gridScale: root.markSize / root.grid
|
|
21
|
+
property real strokeWidth: Theme.strokeWidth
|
|
22
|
+
// The solid part of the mark (Icons.js FILLED), empty for every mark but the few that have one.
|
|
23
|
+
readonly property string filledPath: Icons.filledPathFor(root.name)
|
|
24
|
+
// Built the first time a mark names a solid part: a plain glyph owns no object for it, which tests/rowcost.qml counts.
|
|
25
|
+
property Item solid: null
|
|
26
|
+
function syncSolid() {
|
|
27
|
+
if (root.solid === null && root.filledPath.length > 0)
|
|
28
|
+
root.solid = Qt.createComponent("GlyphSolid.qml").createObject(root, { glyph: root })
|
|
29
|
+
}
|
|
30
|
+
// filledPath starts empty, so its first non-empty value, on a build or a reuse, lands here.
|
|
31
|
+
onFilledPathChanged: root.syncSolid()
|
|
32
|
+
|
|
33
|
+
// The Shape is sized in grid units pre-transform; Scale's origin defaults to (0,0), so this
|
|
34
|
+
// offset is what re-centers the scaled-down box in root's slot instead of pinning it top-left.
|
|
35
|
+
Shape {
|
|
36
|
+
width: root.grid
|
|
37
|
+
height: root.grid
|
|
38
|
+
x: (root.width - root.markSize) / 2
|
|
39
|
+
y: (root.height - root.markSize) / 2
|
|
40
|
+
preferredRendererType: Shape.CurveRenderer
|
|
41
|
+
transform: Scale { xScale: root.gridScale; yScale: root.gridScale }
|
|
42
|
+
|
|
43
|
+
ShapePath {
|
|
44
|
+
strokeColor: root.color
|
|
45
|
+
fillColor: "transparent"
|
|
46
|
+
strokeWidth: root.strokeWidth
|
|
47
|
+
// The Omarchy cut: square caps and mitered joins, the edge of the brand spiral; Icons.js paths are redrawn sharp to match.
|
|
48
|
+
capStyle: ViewState.hyprlandIcons && Style.cornerRadius > 0 ? ShapePath.RoundCap : ShapePath.SquareCap
|
|
49
|
+
joinStyle: ViewState.hyprlandIcons && Style.cornerRadius > 0 ? ShapePath.RoundJoin : ShapePath.MiterJoin
|
|
50
|
+
// A mark with more than one stroke is one multi-subpath SVG string; see Icons.js "Lucide path data".
|
|
51
|
+
PathSvg { path: Icons.pathFor(root.name) }
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import QtQuick
|
|
2
|
+
import QtQuick.Shapes
|
|
3
|
+
|
|
4
|
+
// The solid part of a mark, drawn over its stroke in the same ink; ui/Glyph.qml builds it only for a mark that names one.
|
|
5
|
+
Shape {
|
|
6
|
+
id: root
|
|
7
|
+
|
|
8
|
+
required property Glyph glyph
|
|
9
|
+
|
|
10
|
+
width: root.glyph.grid
|
|
11
|
+
height: root.glyph.grid
|
|
12
|
+
x: (root.glyph.width - root.glyph.markSize) / 2
|
|
13
|
+
y: (root.glyph.height - root.glyph.markSize) / 2
|
|
14
|
+
preferredRendererType: Shape.CurveRenderer
|
|
15
|
+
transform: Scale { xScale: root.glyph.gridScale; yScale: root.glyph.gridScale }
|
|
16
|
+
|
|
17
|
+
ShapePath {
|
|
18
|
+
strokeColor: "transparent"
|
|
19
|
+
fillColor: root.glyph.color
|
|
20
|
+
PathSvg { path: root.glyph.filledPath }
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import QtQuick
|
|
2
|
+
import "js/Motion.js" as Motion
|
|
3
|
+
|
|
4
|
+
// The one fade every dialog and menu shares: OutCubic, Motion.durMs.open in and .close out, snapped under reduced motion.
|
|
5
|
+
QtObject {
|
|
6
|
+
id: root
|
|
7
|
+
|
|
8
|
+
// The item that fades; it declares a plain `opacity: 0` and never binds it.
|
|
9
|
+
property Item target: null
|
|
10
|
+
property bool shown: false
|
|
11
|
+
// A dialog's card: it rises Motion.translateUpPx into place on a fresh open only, and never moves while it fades out.
|
|
12
|
+
property Item lift: null
|
|
13
|
+
|
|
14
|
+
// Drives target.opacity from where it stands, so a reopen during a close fades up from there and never replays the old frame.
|
|
15
|
+
function drive() {
|
|
16
|
+
if (root.target === null) return
|
|
17
|
+
fade.stop()
|
|
18
|
+
risen.stop()
|
|
19
|
+
if (Theme.reducedMotion) {
|
|
20
|
+
root.target.opacity = root.shown ? 1 : 0
|
|
21
|
+
rise.y = 0
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
if (root.shown && root.lift !== null) {
|
|
25
|
+
if (root.target.opacity === 0) rise.y = Motion.translateUpPx
|
|
26
|
+
if (rise.y !== 0) risen.start()
|
|
27
|
+
}
|
|
28
|
+
fade.to = root.shown ? 1 : 0
|
|
29
|
+
fade.duration = root.shown ? Motion.durMs.open : Motion.durMs.close
|
|
30
|
+
fade.start()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
onShownChanged: root.drive()
|
|
34
|
+
Component.onCompleted: {
|
|
35
|
+
if (root.lift !== null) root.lift.transform = rise
|
|
36
|
+
if (root.shown) root.drive()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
property Translate rise: Translate {}
|
|
40
|
+
property NumberAnimation fade: NumberAnimation {
|
|
41
|
+
target: root.target
|
|
42
|
+
property: "opacity"
|
|
43
|
+
easing.type: Easing.OutCubic
|
|
44
|
+
// A close cut inside the rise leaves the card where it stood until it is gone, then rests it.
|
|
45
|
+
onFinished: if (!root.shown) root.rise.y = 0
|
|
46
|
+
}
|
|
47
|
+
property NumberAnimation risen: NumberAnimation {
|
|
48
|
+
target: root.rise
|
|
49
|
+
property: "y"
|
|
50
|
+
to: 0
|
|
51
|
+
duration: Motion.durMs.open
|
|
52
|
+
easing.type: Easing.OutCubic
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import QtQuick
|
|
2
|
+
|
|
3
|
+
// The Display board's seven-stop ruler: one tick per size Omarchy offers, each carrying its own
|
|
4
|
+
// number, with the stop in force marked by a taller tick under a foreground number rather than by a
|
|
5
|
+
// fill nobody could read (SettingsRest rule 2). The marked tick takes the accent once an override
|
|
6
|
+
// makes the ruler the control, which is the Blueprint's own rule for an active control against a
|
|
7
|
+
// quiet one, and stays muted while Omarchy owns the size and the ruler is only reporting it.
|
|
8
|
+
Item {
|
|
9
|
+
id: root
|
|
10
|
+
|
|
11
|
+
property var stops: []
|
|
12
|
+
// The last filled tick. Omarchy can be on a size that is not a stop, so the caller fills to the
|
|
13
|
+
// nearest one rather than leaving the ruler blank.
|
|
14
|
+
property int index: -1
|
|
15
|
+
property bool active: false
|
|
16
|
+
|
|
17
|
+
signal picked(int stop)
|
|
18
|
+
|
|
19
|
+
readonly property int tickGap: Theme.spacing.hairline * 2
|
|
20
|
+
readonly property int tickHeight: Theme.spacing.hairline * 3
|
|
21
|
+
// The board's own 7 against 11: the stop in force stands taller, so the mark is never a colour alone.
|
|
22
|
+
readonly property int markedHeight: Theme.spacing.hairline * 5
|
|
23
|
+
// And the board's own 2 against 3 across; the tap target is the slot behind the ink, so a mark this narrow still answers a click anywhere on its stop.
|
|
24
|
+
readonly property int tickInk: Theme.spacing.hairline * 2
|
|
25
|
+
readonly property int markedInk: Theme.spacing.hairline * 3
|
|
26
|
+
// The hairline treatment the panel already uses for a quiet edge, so an unmarked stop reads as one.
|
|
27
|
+
readonly property real restOpacity: 0.4
|
|
28
|
+
readonly property real tickWidth: root.stops.length > 0
|
|
29
|
+
? (root.width - root.tickGap * (root.stops.length - 1)) / root.stops.length : 0
|
|
30
|
+
readonly property real numberHeight: Theme.font.caption * 1.5
|
|
31
|
+
// WCAG 2.5.8's floor under the tap target, whatever height the numbers and ticks come to.
|
|
32
|
+
readonly property int hitHeight: Math.max(Theme.hitMin, Math.round(root.numberHeight + root.markedHeight))
|
|
33
|
+
|
|
34
|
+
implicitHeight: root.hitHeight
|
|
35
|
+
|
|
36
|
+
Repeater {
|
|
37
|
+
model: root.stops
|
|
38
|
+
|
|
39
|
+
delegate: Item {
|
|
40
|
+
id: tick
|
|
41
|
+
required property var modelData
|
|
42
|
+
required property int index
|
|
43
|
+
readonly property bool marked: tick.index === root.index
|
|
44
|
+
|
|
45
|
+
// The hit box is taller than the drawn tick and centred on the ruler, so it moves nothing.
|
|
46
|
+
x: tick.index * (root.tickWidth + root.tickGap)
|
|
47
|
+
y: Math.round((root.height - tick.height) / 2)
|
|
48
|
+
width: root.tickWidth
|
|
49
|
+
height: root.hitHeight
|
|
50
|
+
|
|
51
|
+
Text {
|
|
52
|
+
id: number
|
|
53
|
+
anchors.horizontalCenter: parent.horizontalCenter
|
|
54
|
+
y: Math.round((root.numberHeight - implicitHeight) / 2)
|
|
55
|
+
text: tick.modelData
|
|
56
|
+
color: tick.marked ? Theme.color.foreground : Theme.color.muted
|
|
57
|
+
opacity: tick.marked ? 1 : root.restOpacity
|
|
58
|
+
font.family: Theme.font.family
|
|
59
|
+
font.pixelSize: Theme.font.caption
|
|
60
|
+
textFormat: Text.PlainText
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
Rectangle {
|
|
64
|
+
anchors.horizontalCenter: parent.horizontalCenter
|
|
65
|
+
y: Math.round(root.numberHeight)
|
|
66
|
+
width: tick.marked ? root.markedInk : root.tickInk
|
|
67
|
+
height: tick.marked ? root.markedHeight : root.tickHeight
|
|
68
|
+
color: root.active && tick.marked ? Theme.color.accent : Theme.color.mutedFrame
|
|
69
|
+
opacity: tick.marked ? 1 : root.restOpacity
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
HoverHandler {
|
|
73
|
+
enabled: root.active
|
|
74
|
+
cursorShape: Qt.PointingHandCursor
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
TapHandler {
|
|
78
|
+
enabled: root.active
|
|
79
|
+
acceptedButtons: Qt.LeftButton
|
|
80
|
+
gesturePolicy: TapHandler.ReleaseWithinBounds
|
|
81
|
+
onTapped: root.picked(tick.modelData)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import QtQuick
|
|
2
|
+
import "." as Flea
|
|
3
|
+
import "js/Buttons.js" as Buttons
|
|
4
|
+
|
|
5
|
+
// The Display board's two-value control: both names side by side, the current one bright, rather than
|
|
6
|
+
// the chevron walk a longer list needs. ui/SettingsRow.qml draws it for any row whose model names its
|
|
7
|
+
// options, and the row above owns the writer, so nothing here holds state.
|
|
8
|
+
Row {
|
|
9
|
+
id: root
|
|
10
|
+
|
|
11
|
+
property var options: []
|
|
12
|
+
property string value: ""
|
|
13
|
+
property var glyphs: []
|
|
14
|
+
// A host that puts the row in its Tab order (a dialog's Format) sets this; Settings never focuses it.
|
|
15
|
+
property bool tabStop: false
|
|
16
|
+
// The hit minimum in Settings; a chrome strip hosts the same cells at its control height.
|
|
17
|
+
property int cellHeight: Theme.hitMin
|
|
18
|
+
|
|
19
|
+
// The option a pointer chose, which is never the one already showing.
|
|
20
|
+
signal picked(int index)
|
|
21
|
+
|
|
22
|
+
spacing: Theme.spacing.hairline * Buttons.SEGMENT_GAP
|
|
23
|
+
|
|
24
|
+
Repeater {
|
|
25
|
+
model: root.options
|
|
26
|
+
|
|
27
|
+
delegate: Rectangle {
|
|
28
|
+
id: segment
|
|
29
|
+
required property var modelData
|
|
30
|
+
required property int index
|
|
31
|
+
|
|
32
|
+
readonly property bool current: segment.modelData === root.value
|
|
33
|
+
readonly property string glyph: root.glyphs[segment.index] || ""
|
|
34
|
+
// A segment that takes the keyboard (a dialog's Tab stop) marks its current cell as DialogButton marks a focused set member.
|
|
35
|
+
readonly property bool focusedHere: root.tabStop && segment.current && root.activeFocus && segment.glyph.length === 0
|
|
36
|
+
// Accent where it has hue, else RING wide in the foreground, both inside the cell like DialogButton's set member.
|
|
37
|
+
readonly property string focusFrame: Buttons.focusFrame(Theme.color.accentHasHue, true, false)
|
|
38
|
+
|
|
39
|
+
// The WCAG floor the Blueprint sets for a compact control, which this row has room for.
|
|
40
|
+
width: segment.glyph ? Math.max(Theme.hitMin, Theme.railIconSize + 2 * (Theme.spacing.gap - Theme.spacing.hairline))
|
|
41
|
+
: name.implicitWidth + 2 * Theme.spacing.gap
|
|
42
|
+
height: root.cellHeight
|
|
43
|
+
// Containers rule 4: a segmented cell is never filled, so the choice reads as brightness.
|
|
44
|
+
color: "transparent"
|
|
45
|
+
// Rule 3: words in a set are Tier B and every member wears the box; glyphs in a strip are
|
|
46
|
+
// Tier A, where a box around four marks would be furniture.
|
|
47
|
+
border.width: segment.glyph ? 0 : segment.focusedHere && segment.focusFrame === "thick" ? Buttons.RING : Theme.spacing.hairline
|
|
48
|
+
border.color: segment.focusedHere && segment.focusFrame === "accent" ? Theme.color.accent
|
|
49
|
+
: segment.current ? Theme.color.foreground : Theme.color.mutedFrame
|
|
50
|
+
Accessible.role: Accessible.Button
|
|
51
|
+
Accessible.name: String(segment.modelData)
|
|
52
|
+
Accessible.onPressAction: root.picked(segment.index)
|
|
53
|
+
|
|
54
|
+
Flea.Glyph {
|
|
55
|
+
anchors.centerIn: parent
|
|
56
|
+
visible: segment.glyph.length > 0
|
|
57
|
+
width: Theme.railIconSize
|
|
58
|
+
height: width
|
|
59
|
+
name: segment.glyph || "file"
|
|
60
|
+
color: segment.current ? Theme.color.foreground : Theme.color.mutedFrame
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
Text {
|
|
64
|
+
id: name
|
|
65
|
+
visible: segment.glyph.length === 0
|
|
66
|
+
anchors.centerIn: parent
|
|
67
|
+
text: segment.modelData
|
|
68
|
+
color: segment.current ? Theme.color.foreground : Theme.color.muted
|
|
69
|
+
font.family: Theme.font.family
|
|
70
|
+
font.pixelSize: Theme.font.caption
|
|
71
|
+
textFormat: Text.PlainText
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
HoverHandler {
|
|
75
|
+
cursorShape: Qt.PointingHandCursor
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
TapHandler {
|
|
79
|
+
acceptedButtons: Qt.LeftButton
|
|
80
|
+
gesturePolicy: TapHandler.ReleaseWithinBounds
|
|
81
|
+
onTapped: if (!segment.current) root.picked(segment.index)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import QtQuick
|
|
2
|
+
import QtQml.Models
|
|
3
|
+
|
|
4
|
+
// A view's row count as a model that never changes identity, so a new count keeps the delegates that stay drawn.
|
|
5
|
+
DelegateModel {
|
|
6
|
+
id: root
|
|
7
|
+
|
|
8
|
+
required property Item view
|
|
9
|
+
property int total: 0
|
|
10
|
+
// The compositor is filled in componentComplete, so a group change before onCompleted is silently dropped.
|
|
11
|
+
property bool ready: false
|
|
12
|
+
|
|
13
|
+
// A move asked for inside the change's own layout is dropped, so a view that places itself does it here.
|
|
14
|
+
signal resized()
|
|
15
|
+
|
|
16
|
+
// Qt refuses an integer model larger than 100,000,000 rows.
|
|
17
|
+
readonly property int cap: 100000000
|
|
18
|
+
model: root.cap
|
|
19
|
+
groups: DelegateModelGroup { id: shown; name: "shown"; includeByDefault: false }
|
|
20
|
+
filterOnGroup: "shown"
|
|
21
|
+
|
|
22
|
+
// While true a view short of a viewport keeps a full layout's delegates in its reuse pool, so a count that grows takes them instead of building.
|
|
23
|
+
property bool warm: false
|
|
24
|
+
// The rows a full layout from the top builds, its cache buffer's included: the fill lays out no more, so none is left incubating.
|
|
25
|
+
property int warmRows: 0
|
|
26
|
+
|
|
27
|
+
// While true a count change leaves the current delegate current: Qt focuses each new current delegate, which takes the keys from an editor inside the old one.
|
|
28
|
+
property bool holdCurrent: false
|
|
29
|
+
|
|
30
|
+
onTotalChanged: root.resize()
|
|
31
|
+
onWarmChanged: if (root.warm) root.fill()
|
|
32
|
+
Component.onCompleted: { root.ready = true; root.resize() }
|
|
33
|
+
|
|
34
|
+
// Grows the count and shrinks it back in one turn, so no frame sees the rows and what they laid out waits pooled; a geometry change drains it.
|
|
35
|
+
function fill() {
|
|
36
|
+
var from = shown.count
|
|
37
|
+
var to = Math.min(root.warmRows, root.cap)
|
|
38
|
+
if (!root.ready || !root.view.reuseItems || to <= from)
|
|
39
|
+
return
|
|
40
|
+
// The buffer's rows lay out with the viewport's for this pass, built at once where a buffer pass would incubate them later.
|
|
41
|
+
var margin = root.view.displayMarginEnd
|
|
42
|
+
root.view.displayMarginEnd = margin + root.view.cacheBuffer + root.view.height
|
|
43
|
+
root.items.addGroups(from, to - from, "shown")
|
|
44
|
+
root.view.forceLayout()
|
|
45
|
+
shown.removeGroups(from, to - from, "shown")
|
|
46
|
+
root.view.forceLayout()
|
|
47
|
+
root.view.displayMarginEnd = margin
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Moves to the top and, unless holdCurrent, row 0 as a reset does, before the change, so only top rows lay out and a view placing itself after keeps its place.
|
|
51
|
+
function resize() {
|
|
52
|
+
var to = Math.min(Math.max(root.total, 0), root.cap)
|
|
53
|
+
var from = shown.count
|
|
54
|
+
if (!root.ready || to === from)
|
|
55
|
+
return
|
|
56
|
+
root.view.contentY = root.view.originY - root.view.topMargin
|
|
57
|
+
if (from > 0 && to > 0 && !root.holdCurrent)
|
|
58
|
+
root.view.currentIndex = 0
|
|
59
|
+
if (to > from)
|
|
60
|
+
root.items.addGroups(from, to - from, "shown")
|
|
61
|
+
else
|
|
62
|
+
shown.removeGroups(to, from - to, "shown")
|
|
63
|
+
// Lays out now: Qt pools a layout's removed rows only after building its inserted ones, so the next count reuses them.
|
|
64
|
+
root.view.forceLayout()
|
|
65
|
+
if (to > 0 && root.view.currentIndex < 0)
|
|
66
|
+
root.view.currentIndex = 0
|
|
67
|
+
root.resized()
|
|
68
|
+
if (to === 0)
|
|
69
|
+
root.drainHidden()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// True where a hidden count is rows kept for the return rather than an edit in flight, so the hide drains the pool beside them.
|
|
73
|
+
property bool keptRows: false
|
|
74
|
+
// A hidden view holds no delegates, pooled ones included; a shown one keeps its pool, parked, for the next listing.
|
|
75
|
+
function drainHidden() {
|
|
76
|
+
if (root.view.visible || shown.count > 0 && !root.keptRows || !root.view.reuseItems)
|
|
77
|
+
return
|
|
78
|
+
// Unpersist first so the pool toggle below frees the parked tiles too.
|
|
79
|
+
if (persistedItems.count > 0)
|
|
80
|
+
persistedItems.removeGroups(0, persistedItems.count, "persistedItems")
|
|
81
|
+
root.view.reuseItems = false
|
|
82
|
+
root.view.reuseItems = true
|
|
83
|
+
}
|
|
84
|
+
// A view hidden after it emptied drains here, since its count does not change again.
|
|
85
|
+
property Connections hiding: Connections {
|
|
86
|
+
target: root.view
|
|
87
|
+
function onVisibleChanged() { root.drainHidden() }
|
|
88
|
+
}
|
|
89
|
+
}
|